mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-29 20:23:24 +00:00
fix(fs, mm): 修复fs、mm上有关系统调用的bug (#1208)
* fix(fs, mm): 修复fs、mm上有关系统调用的bug **filesystem:** - 修改read系统调用:修复`O_PATH`文件模式该有的功能,使其能通过gvisor/syscall/read的测试。参考:[[file_table.c - fs/file_table.c - Linux source code v2.6.39 - Bootlin Elixir Cross Referencer](https://elixir.bootlin.com/linux/v2.6.39/source/fs/file_table.c#L331)](https://elixir.bootlin.com/linux/v2.6.39/source/fs/file_table.c#L331),在读取之前先进行检查文件模式是否为`O_PATH` - 修改getcwd系统调用:修正成跟linux语义一样,返回目录长度而不是地址。因为gvisor用这个系统调用如果返回的是地址是会报错的,改成跟linux一样就不会报错了。参考:[[dcache.c - fs/dcache.c - Linux source code v2.6.39 - Bootlin Elixir Cross Referencer](https://elixir.bootlin.com/linux/v2.6.39/source/fs/dcache.c#L2774)](https://elixir.bootlin.com/linux/v2.6.39/source/fs/dcache.c#L2774) - 修改unlink系统调用:在unlink删除inode之后,要将inode对应的pagecache的dirty标识去掉,否则在`flush_dirty_pages()`的时候,会将标记为dirty的pagecache进行`page_writeback()`,但是对应的pagecache的inode已经被释放了,这时候直接unwrap()就会导致panic。参考:[[namei.c - fs/namei.c - Linux source code v2.6.6 - Bootlin Elixir Cross Referencer](https://elixir.bootlin.com/linux/v2.6.6/source/fs/namei.c#L1714)](https://elixir.bootlin.com/linux/v2.6.6/source/fs/namei.c#L1714) **mm:** - 添加`truncate_inode_pages()`,用来截断文件从指定偏移量的页缓存,但目前该函数功能仅是将pagecache的dirty标识去掉。参考:[[truncate.c - mm/truncate.c - Linux source code v2.6.6 - Bootlin Elixir Cross Referencer](https://elixir.bootlin.com/linux/v2.6.6/source/mm/truncate.c#L112)](https://elixir.bootlin.com/linux/v2.6.6/source/mm/truncate.c#L112) **syscall:** - 修改了`convert_with_offset()`的判断逻辑,使其能够从用户空间读取0字节的数据,也是为了能够通过gvisor/syscall/read的测试 目前是能够跑通gvisor syscall测试`read_test`并通过所有测例 
This commit is contained in:
@ -312,6 +312,10 @@ impl InnerPageCache {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn pages_count(&self) -> usize {
|
||||
return self.pages.len();
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for InnerPageCache {
|
||||
|
@ -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<VirtAddr, SystemError> {
|
||||
pub fn getcwd(buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
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);
|
||||
}
|
||||
|
||||
/// # 获取目录中的数据
|
||||
|
@ -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<usize, SystemError> {
|
||||
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);
|
||||
}
|
||||
|
@ -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<u64, SystemError> {
|
||||
}
|
||||
}
|
||||
// 禁止在目录上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<u64, SystemError> {
|
||||
// 删除文件
|
||||
parent_inode.unlink(filename)?;
|
||||
|
||||
if let Some(page_cache) = inode.unwrap().page_cache().clone() {
|
||||
truncate_inode_pages(page_cache, 0);
|
||||
}
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
|
@ -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中初始化)
|
||||
|
32
kernel/src/mm/truncate.rs
Normal file
32
kernel/src/mm/truncate.rs
Normal file
@ -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<PageCache>, 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<PageCache>, page: Arc<Page>) {
|
||||
let mut guard = page.write_irqsave();
|
||||
guard.remove_flags(PageFlags::PG_DIRTY);
|
||||
}
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -334,11 +334,11 @@ impl<'a> UserBufferWriter<'a> {
|
||||
}
|
||||
|
||||
fn convert_with_offset<T>(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::<T>() != 0 || byte_buffer.is_empty() {
|
||||
if byte_buffer.len() % core::mem::size_of::<T>() != 0 {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user