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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pages_count(&self) -> usize {
|
||||||
|
return self.pages.len();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for InnerPageCache {
|
impl Drop for InnerPageCache {
|
||||||
|
@ -13,7 +13,6 @@ use crate::{
|
|||||||
driver::base::{block::SeekFrom, device::device_number::DeviceNumber},
|
driver::base::{block::SeekFrom, device::device_number::DeviceNumber},
|
||||||
filesystem::vfs::{file::FileDescriptorVec, vcore as Vcore},
|
filesystem::vfs::{file::FileDescriptorVec, vcore as Vcore},
|
||||||
libs::rwlock::RwLockWriteGuard,
|
libs::rwlock::RwLockWriteGuard,
|
||||||
mm::VirtAddr,
|
|
||||||
process::ProcessManager,
|
process::ProcessManager,
|
||||||
syscall::{
|
syscall::{
|
||||||
user_access::{self, check_and_clone_cstr, UserBufferWriter},
|
user_access::{self, check_and_clone_cstr, UserBufferWriter},
|
||||||
@ -633,7 +632,7 @@ impl Syscall {
|
|||||||
///
|
///
|
||||||
/// @return 成功,返回的指针指向包含工作目录路径的字符串
|
/// @return 成功,返回的指针指向包含工作目录路径的字符串
|
||||||
/// @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 proc = ProcessManager::current_pcb();
|
||||||
let cwd = proc.basic().cwd();
|
let cwd = proc.basic().cwd();
|
||||||
|
|
||||||
@ -645,7 +644,7 @@ impl Syscall {
|
|||||||
buf[..cwd_len].copy_from_slice(cwd_bytes);
|
buf[..cwd_len].copy_from_slice(cwd_bytes);
|
||||||
buf[cwd_len] = 0;
|
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::interrupt::TrapFrame;
|
||||||
use crate::arch::syscall::nr::SYS_READ;
|
use crate::arch::syscall::nr::SYS_READ;
|
||||||
|
use crate::filesystem::vfs::file::FileMode;
|
||||||
use crate::process::ProcessManager;
|
use crate::process::ProcessManager;
|
||||||
use crate::syscall::table::FormattedSyscallParam;
|
use crate::syscall::table::FormattedSyscallParam;
|
||||||
use crate::syscall::table::Syscall;
|
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 binding = ProcessManager::current_pcb().fd_table();
|
||||||
let fd_table_guard = binding.read();
|
let fd_table_guard = binding.read();
|
||||||
|
|
||||||
let file = fd_table_guard.get_file_by_fd(fd);
|
let file = fd_table_guard
|
||||||
if file.is_none() {
|
.get_file_by_fd(fd)
|
||||||
return Err(SystemError::EBADF);
|
.ok_or(SystemError::EBADF)?;
|
||||||
}
|
|
||||||
// drop guard 以避免无法调度的问题
|
// drop guard 以避免无法调度的问题
|
||||||
drop(fd_table_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);
|
return file.read(buf.len(), buf);
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
libs::spinlock::SpinLock,
|
libs::spinlock::SpinLock,
|
||||||
|
mm::truncate::truncate_inode_pages,
|
||||||
process::ProcessManager,
|
process::ProcessManager,
|
||||||
syscall::user_access::check_and_clone_cstr,
|
syscall::user_access::check_and_clone_cstr,
|
||||||
};
|
};
|
||||||
@ -262,7 +263,7 @@ pub fn do_unlink_at(dirfd: i32, path: &str) -> Result<u64, SystemError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 禁止在目录上unlink
|
// 禁止在目录上unlink
|
||||||
if inode.unwrap().metadata()?.file_type == FileType::Dir {
|
if inode.as_ref().unwrap().metadata()?.file_type == FileType::Dir {
|
||||||
return Err(SystemError::EPERM);
|
return Err(SystemError::EPERM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,6 +279,10 @@ pub fn do_unlink_at(dirfd: i32, path: &str) -> Result<u64, SystemError> {
|
|||||||
// 删除文件
|
// 删除文件
|
||||||
parent_inode.unlink(filename)?;
|
parent_inode.unlink(filename)?;
|
||||||
|
|
||||||
|
if let Some(page_cache) = inode.unwrap().page_cache().clone() {
|
||||||
|
truncate_inode_pages(page_cache, 0);
|
||||||
|
}
|
||||||
|
|
||||||
return Ok(0);
|
return Ok(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ pub mod no_init;
|
|||||||
pub mod page;
|
pub mod page;
|
||||||
pub mod percpu;
|
pub mod percpu;
|
||||||
pub mod syscall;
|
pub mod syscall;
|
||||||
|
pub mod truncate;
|
||||||
pub mod ucontext;
|
pub mod ucontext;
|
||||||
|
|
||||||
/// 内核INIT进程的用户地址空间结构体(仅在process_init中初始化)
|
/// 内核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)
|
Err(e)
|
||||||
} else {
|
} else {
|
||||||
let buf = unsafe { core::slice::from_raw_parts_mut(buf, size) };
|
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> {
|
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);
|
return Err(SystemError::EINVAL);
|
||||||
}
|
}
|
||||||
let byte_buffer: &mut [u8] = &mut src[offset..];
|
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);
|
return Err(SystemError::EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user