diff --git a/kernel/src/filesystem/page_cache.rs b/kernel/src/filesystem/page_cache.rs index c5902a02..b77e3fdf 100644 --- a/kernel/src/filesystem/page_cache.rs +++ b/kernel/src/filesystem/page_cache.rs @@ -312,6 +312,10 @@ impl InnerPageCache { Ok(()) } + + pub fn pages_count(&self) -> usize { + return self.pages.len(); + } } impl Drop for InnerPageCache { diff --git a/kernel/src/filesystem/vfs/syscall/mod.rs b/kernel/src/filesystem/vfs/syscall/mod.rs index 813a757f..ee841abf 100644 --- a/kernel/src/filesystem/vfs/syscall/mod.rs +++ b/kernel/src/filesystem/vfs/syscall/mod.rs @@ -13,7 +13,6 @@ use crate::{ driver::base::{block::SeekFrom, device::device_number::DeviceNumber}, filesystem::vfs::{file::FileDescriptorVec, vcore as Vcore}, libs::rwlock::RwLockWriteGuard, - mm::VirtAddr, process::ProcessManager, syscall::{ user_access::{self, check_and_clone_cstr, UserBufferWriter}, @@ -633,7 +632,7 @@ impl Syscall { /// /// @return 成功,返回的指针指向包含工作目录路径的字符串 /// @return 错误,没有足够的空间 - pub fn getcwd(buf: &mut [u8]) -> Result { + pub fn getcwd(buf: &mut [u8]) -> Result { let proc = ProcessManager::current_pcb(); let cwd = proc.basic().cwd(); @@ -645,7 +644,7 @@ impl Syscall { buf[..cwd_len].copy_from_slice(cwd_bytes); buf[cwd_len] = 0; - return Ok(VirtAddr::new(buf.as_ptr() as usize)); + return Ok(cwd_len + 1); } /// # 获取目录中的数据 diff --git a/kernel/src/filesystem/vfs/syscall/sys_read.rs b/kernel/src/filesystem/vfs/syscall/sys_read.rs index 2d57c77c..b4cd26a0 100644 --- a/kernel/src/filesystem/vfs/syscall/sys_read.rs +++ b/kernel/src/filesystem/vfs/syscall/sys_read.rs @@ -2,6 +2,7 @@ use system_error::SystemError; use crate::arch::interrupt::TrapFrame; use crate::arch::syscall::nr::SYS_READ; +use crate::filesystem::vfs::file::FileMode; use crate::process::ProcessManager; use crate::syscall::table::FormattedSyscallParam; use crate::syscall::table::Syscall; @@ -93,13 +94,16 @@ pub(super) fn do_read(fd: i32, buf: &mut [u8]) -> Result { let binding = ProcessManager::current_pcb().fd_table(); let fd_table_guard = binding.read(); - let file = fd_table_guard.get_file_by_fd(fd); - if file.is_none() { - return Err(SystemError::EBADF); - } + let file = fd_table_guard + .get_file_by_fd(fd) + .ok_or(SystemError::EBADF)?; + // drop guard 以避免无法调度的问题 drop(fd_table_guard); - let file = file.unwrap(); + + if file.mode().contains(FileMode::O_PATH) { + return Err(SystemError::EBADF); + } return file.read(buf.len(), buf); } diff --git a/kernel/src/filesystem/vfs/vcore.rs b/kernel/src/filesystem/vfs/vcore.rs index b96796f0..5764652f 100644 --- a/kernel/src/filesystem/vfs/vcore.rs +++ b/kernel/src/filesystem/vfs/vcore.rs @@ -18,6 +18,7 @@ use crate::{ }, }, libs::spinlock::SpinLock, + mm::truncate::truncate_inode_pages, process::ProcessManager, syscall::user_access::check_and_clone_cstr, }; @@ -262,7 +263,7 @@ pub fn do_unlink_at(dirfd: i32, path: &str) -> Result { } } // 禁止在目录上unlink - if inode.unwrap().metadata()?.file_type == FileType::Dir { + if inode.as_ref().unwrap().metadata()?.file_type == FileType::Dir { return Err(SystemError::EPERM); } @@ -278,6 +279,10 @@ pub fn do_unlink_at(dirfd: i32, path: &str) -> Result { // 删除文件 parent_inode.unlink(filename)?; + if let Some(page_cache) = inode.unwrap().page_cache().clone() { + truncate_inode_pages(page_cache, 0); + } + return Ok(0); } diff --git a/kernel/src/mm/mod.rs b/kernel/src/mm/mod.rs index 4df64ee0..3944c995 100644 --- a/kernel/src/mm/mod.rs +++ b/kernel/src/mm/mod.rs @@ -32,6 +32,7 @@ pub mod no_init; pub mod page; pub mod percpu; pub mod syscall; +pub mod truncate; pub mod ucontext; /// 内核INIT进程的用户地址空间结构体(仅在process_init中初始化) diff --git a/kernel/src/mm/truncate.rs b/kernel/src/mm/truncate.rs new file mode 100644 index 00000000..bc3f1269 --- /dev/null +++ b/kernel/src/mm/truncate.rs @@ -0,0 +1,32 @@ +use super::page::{Page, PageFlags}; +use crate::filesystem::page_cache::PageCache; +use alloc::sync::Arc; + +/// # 功能 +/// +/// 从指定偏移量开始,截断与当前文件的所有页缓存,目前仅是将文件相关的页缓存页的dirty位去除 +/// +/// # 参数 +/// +/// - page_cache: 与文件inode关联的页缓存 +/// - start: 偏移量 +pub fn truncate_inode_pages(page_cache: Arc, start: usize) { + let guard = page_cache.lock_irqsave(); + let pages_count = guard.pages_count(); + + for i in start..pages_count { + let page = guard.get_page(i); + let page = if let Some(page) = page { + page + } else { + log::warn!("try to truncate page from different page cache"); + return; + }; + truncate_complete_page(page_cache.clone(), page.clone()); + } +} + +fn truncate_complete_page(_page_cache: Arc, page: Arc) { + let mut guard = page.write_irqsave(); + guard.remove_flags(PageFlags::PG_DIRTY); +} diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index 99057fd3..13a58529 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -505,7 +505,7 @@ impl Syscall { Err(e) } else { let buf = unsafe { core::slice::from_raw_parts_mut(buf, size) }; - Self::getcwd(buf).map(|ptr| ptr.data()) + Self::getcwd(buf) } } diff --git a/kernel/src/syscall/user_access.rs b/kernel/src/syscall/user_access.rs index 36c3fe09..5fab8ba3 100644 --- a/kernel/src/syscall/user_access.rs +++ b/kernel/src/syscall/user_access.rs @@ -334,11 +334,11 @@ impl<'a> UserBufferWriter<'a> { } fn convert_with_offset(src: &mut [u8], offset: usize) -> Result<&mut [T], SystemError> { - if offset >= src.len() { + if offset > src.len() { return Err(SystemError::EINVAL); } let byte_buffer: &mut [u8] = &mut src[offset..]; - if byte_buffer.len() % core::mem::size_of::() != 0 || byte_buffer.is_empty() { + if byte_buffer.len() % core::mem::size_of::() != 0 { return Err(SystemError::EINVAL); }