mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 10:15:03 +00:00
fix(mm): 修复fat文件系统的PageCache同步问题 (#1005)
--------- Co-authored-by: longjin <longjin@DragonOS.org>
This commit is contained in:
parent
a08191c719
commit
e92424df8d
@ -63,7 +63,6 @@ paste = "=1.0.14"
|
||||
slabmalloc = { path = "crates/rust-slabmalloc" }
|
||||
log = "0.4.21"
|
||||
kprobe = { path = "crates/kprobe" }
|
||||
xarray = "0.1.0"
|
||||
lru = "0.12.3"
|
||||
|
||||
rbpf = { path = "crates/rbpf" }
|
||||
|
@ -3,7 +3,7 @@ use crate::arch::mm::kernel_page_flags;
|
||||
use crate::arch::MMArch;
|
||||
|
||||
use crate::mm::kernel_mapper::KernelMapper;
|
||||
use crate::mm::page::{page_manager_lock_irqsave, EntryFlags};
|
||||
use crate::mm::page::EntryFlags;
|
||||
use crate::mm::{
|
||||
allocator::page_frame::{
|
||||
allocate_page_frames, deallocate_page_frames, PageFrameCount, PhysPageFrame,
|
||||
@ -61,11 +61,7 @@ pub unsafe fn dma_dealloc(paddr: usize, vaddr: NonNull<u8>, pages: usize) -> i32
|
||||
flusher.flush();
|
||||
|
||||
unsafe {
|
||||
deallocate_page_frames(
|
||||
PhysPageFrame::new(PhysAddr::new(paddr)),
|
||||
page_count,
|
||||
&mut page_manager_lock_irqsave(),
|
||||
);
|
||||
deallocate_page_frames(PhysPageFrame::new(PhysAddr::new(paddr)), page_count);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use crate::arch::mm::kernel_page_flags;
|
||||
use crate::arch::MMArch;
|
||||
|
||||
use crate::mm::kernel_mapper::KernelMapper;
|
||||
use crate::mm::page::{page_manager_lock_irqsave, EntryFlags};
|
||||
use crate::mm::page::EntryFlags;
|
||||
use crate::mm::{
|
||||
allocator::page_frame::{
|
||||
allocate_page_frames, deallocate_page_frames, PageFrameCount, PhysPageFrame,
|
||||
@ -72,11 +72,7 @@ unsafe impl Hal for HalImpl {
|
||||
flusher.flush();
|
||||
|
||||
unsafe {
|
||||
deallocate_page_frames(
|
||||
PhysPageFrame::new(PhysAddr::new(paddr)),
|
||||
page_count,
|
||||
&mut page_manager_lock_irqsave(),
|
||||
);
|
||||
deallocate_page_frames(PhysPageFrame::new(PhysAddr::new(paddr)), page_count);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ use alloc::{
|
||||
|
||||
use crate::driver::base::block::gendisk::GenDisk;
|
||||
use crate::driver::base::device::device_number::DeviceNumber;
|
||||
use crate::filesystem::vfs::file::PageCache;
|
||||
use crate::filesystem::page_cache::PageCache;
|
||||
use crate::filesystem::vfs::utils::DName;
|
||||
use crate::filesystem::vfs::{Magic, SpecialNodeData, SuperBlock};
|
||||
use crate::ipc::pipe::LockedPipeInode;
|
||||
@ -129,9 +129,8 @@ pub struct FATInode {
|
||||
}
|
||||
|
||||
impl FATInode {
|
||||
/// @brief 更新当前inode的元数据
|
||||
pub fn update_metadata(&mut self) {
|
||||
// todo: 更新文件的访问时间等信息
|
||||
/// 将inode的元数据与磁盘同步
|
||||
pub fn synchronize_metadata(&mut self) {
|
||||
match &self.inode_type {
|
||||
FATDirEntry::File(f) | FATDirEntry::VolId(f) => {
|
||||
self.metadata.size = f.size() as i64;
|
||||
@ -146,6 +145,19 @@ impl FATInode {
|
||||
};
|
||||
}
|
||||
|
||||
/// 更新inode的元数据
|
||||
pub fn update_metadata(&mut self, size: Option<i64>) {
|
||||
if let Some(new_size) = size {
|
||||
self.metadata.size = new_size;
|
||||
}
|
||||
self.update_time();
|
||||
}
|
||||
|
||||
/// 更新访问时间
|
||||
pub fn update_time(&mut self) {
|
||||
// log::warn!("update_time has not yet been implemented");
|
||||
}
|
||||
|
||||
fn find(&mut self, name: &str) -> Result<Arc<LockedFATInode>, SystemError> {
|
||||
match &self.inode_type {
|
||||
FATDirEntry::Dir(d) => {
|
||||
@ -234,7 +246,7 @@ impl LockedFATInode {
|
||||
|
||||
inode.0.lock().self_ref = Arc::downgrade(&inode);
|
||||
|
||||
inode.0.lock().update_metadata();
|
||||
inode.0.lock().synchronize_metadata();
|
||||
|
||||
return inode;
|
||||
}
|
||||
@ -1386,24 +1398,14 @@ impl FATFsInfo {
|
||||
}
|
||||
|
||||
impl IndexNode for LockedFATInode {
|
||||
fn read_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
len: usize,
|
||||
buf: &mut [u8],
|
||||
_data: SpinLockGuard<FilePrivateData>,
|
||||
) -> Result<usize, SystemError> {
|
||||
let mut guard: SpinLockGuard<FATInode> = self.0.lock();
|
||||
fn read_sync(&self, offset: usize, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
let guard: SpinLockGuard<FATInode> = self.0.lock();
|
||||
match &guard.inode_type {
|
||||
FATDirEntry::File(f) | FATDirEntry::VolId(f) => {
|
||||
let r = f.read(
|
||||
&guard.fs.upgrade().unwrap(),
|
||||
&mut buf[0..len],
|
||||
offset as u64,
|
||||
);
|
||||
guard.update_metadata();
|
||||
let r = f.read(&guard.fs.upgrade().unwrap(), buf, offset as u64);
|
||||
return r;
|
||||
}
|
||||
|
||||
FATDirEntry::Dir(_) => {
|
||||
return Err(SystemError::EISDIR);
|
||||
}
|
||||
@ -1414,30 +1416,93 @@ impl IndexNode for LockedFATInode {
|
||||
}
|
||||
}
|
||||
|
||||
fn write_sync(&self, offset: usize, buf: &[u8]) -> Result<usize, SystemError> {
|
||||
let mut guard: SpinLockGuard<FATInode> = self.0.lock();
|
||||
let fs: &Arc<FATFileSystem> = &guard.fs.upgrade().unwrap();
|
||||
|
||||
match &mut guard.inode_type {
|
||||
FATDirEntry::File(f) | FATDirEntry::VolId(f) => {
|
||||
let r = f.write(fs, buf, offset as u64);
|
||||
return r;
|
||||
}
|
||||
|
||||
FATDirEntry::Dir(_) => {
|
||||
return Err(SystemError::EISDIR);
|
||||
}
|
||||
|
||||
FATDirEntry::UnInit => {
|
||||
error!("FATFS: param: Inode_type uninitialized.");
|
||||
return Err(SystemError::EROFS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn read_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
len: usize,
|
||||
buf: &mut [u8],
|
||||
data: SpinLockGuard<FilePrivateData>,
|
||||
) -> Result<usize, SystemError> {
|
||||
let len = core::cmp::min(len, buf.len());
|
||||
let buf = &mut buf[0..len];
|
||||
|
||||
let page_cache = self.0.lock().page_cache.clone();
|
||||
if let Some(page_cache) = page_cache {
|
||||
let r = page_cache.lock_irqsave().read(offset, &mut buf[0..len]);
|
||||
// self.0.lock_irqsave().update_metadata();
|
||||
return r;
|
||||
} else {
|
||||
return self.read_direct(offset, len, buf, data);
|
||||
}
|
||||
}
|
||||
|
||||
fn write_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
len: usize,
|
||||
buf: &[u8],
|
||||
data: SpinLockGuard<FilePrivateData>,
|
||||
) -> Result<usize, SystemError> {
|
||||
let len = core::cmp::min(len, buf.len());
|
||||
let buf = &buf[0..len];
|
||||
|
||||
let page_cache = self.0.lock().page_cache.clone();
|
||||
if let Some(page_cache) = page_cache {
|
||||
let write_len = page_cache.lock_irqsave().write(offset, buf)?;
|
||||
let mut guard = self.0.lock();
|
||||
let old_size = guard.metadata.size;
|
||||
guard.update_metadata(Some(core::cmp::max(old_size, (offset + write_len) as i64)));
|
||||
return Ok(write_len);
|
||||
} else {
|
||||
return self.write_direct(offset, len, buf, data);
|
||||
}
|
||||
}
|
||||
|
||||
fn read_direct(
|
||||
&self,
|
||||
offset: usize,
|
||||
len: usize,
|
||||
buf: &mut [u8],
|
||||
_data: SpinLockGuard<FilePrivateData>,
|
||||
) -> Result<usize, SystemError> {
|
||||
let len = core::cmp::min(len, buf.len());
|
||||
let r = self.read_sync(offset, &mut buf[0..len]);
|
||||
// self.0.lock_irqsave().update_metadata();
|
||||
return r;
|
||||
}
|
||||
|
||||
fn write_direct(
|
||||
&self,
|
||||
offset: usize,
|
||||
len: usize,
|
||||
buf: &[u8],
|
||||
_data: SpinLockGuard<FilePrivateData>,
|
||||
) -> Result<usize, SystemError> {
|
||||
let mut guard: SpinLockGuard<FATInode> = self.0.lock();
|
||||
let fs: &Arc<FATFileSystem> = &guard.fs.upgrade().unwrap();
|
||||
|
||||
match &mut guard.inode_type {
|
||||
FATDirEntry::File(f) | FATDirEntry::VolId(f) => {
|
||||
let r = f.write(fs, &buf[0..len], offset as u64);
|
||||
guard.update_metadata();
|
||||
return r;
|
||||
}
|
||||
FATDirEntry::Dir(_) => {
|
||||
return Err(SystemError::EISDIR);
|
||||
}
|
||||
FATDirEntry::UnInit => {
|
||||
error!("FATFS: param: Inode_type uninitialized.");
|
||||
return Err(SystemError::EROFS);
|
||||
}
|
||||
}
|
||||
let len = core::cmp::min(len, buf.len());
|
||||
let r = self.write_sync(offset, &buf[0..len]);
|
||||
// self.0.lock_irqsave().update_metadata();
|
||||
return r;
|
||||
}
|
||||
|
||||
fn create(
|
||||
@ -1496,6 +1561,10 @@ impl IndexNode for LockedFATInode {
|
||||
Ok(())
|
||||
}
|
||||
fn resize(&self, len: usize) -> Result<(), SystemError> {
|
||||
if let Some(page_cache) = self.page_cache() {
|
||||
return page_cache.lock_irqsave().resize(len);
|
||||
}
|
||||
|
||||
let mut guard: SpinLockGuard<FATInode> = self.0.lock();
|
||||
let fs: &Arc<FATFileSystem> = &guard.fs.upgrade().unwrap();
|
||||
let old_size = guard.metadata.size as usize;
|
||||
@ -1527,7 +1596,7 @@ impl IndexNode for LockedFATInode {
|
||||
file.truncate(fs, len as u64)?;
|
||||
}
|
||||
}
|
||||
guard.update_metadata();
|
||||
guard.synchronize_metadata();
|
||||
return Ok(());
|
||||
}
|
||||
FATDirEntry::Dir(_) => return Err(SystemError::ENOSYS),
|
||||
|
@ -5,6 +5,7 @@ pub mod fat;
|
||||
pub mod kernfs;
|
||||
pub mod mbr;
|
||||
pub mod overlayfs;
|
||||
pub mod page_cache;
|
||||
pub mod procfs;
|
||||
pub mod ramfs;
|
||||
pub mod sysfs;
|
||||
|
346
kernel/src/filesystem/page_cache.rs
Normal file
346
kernel/src/filesystem/page_cache.rs
Normal file
@ -0,0 +1,346 @@
|
||||
use core::cmp::min;
|
||||
|
||||
use alloc::{
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
use hashbrown::HashMap;
|
||||
use system_error::SystemError;
|
||||
|
||||
use super::vfs::IndexNode;
|
||||
use crate::libs::spinlock::SpinLockGuard;
|
||||
use crate::mm::page::FileMapInfo;
|
||||
use crate::{arch::mm::LockedFrameAllocator, libs::lazy_init::Lazy};
|
||||
use crate::{
|
||||
arch::MMArch,
|
||||
libs::spinlock::SpinLock,
|
||||
mm::{
|
||||
page::{page_manager_lock_irqsave, page_reclaimer_lock_irqsave, Page, PageFlags},
|
||||
MemoryManagementArch,
|
||||
},
|
||||
};
|
||||
use crate::{libs::align::page_align_up, mm::page::PageType};
|
||||
|
||||
/// 页面缓存
|
||||
#[derive(Debug)]
|
||||
pub struct PageCache {
|
||||
inner: SpinLock<InnerPageCache>,
|
||||
inode: Lazy<Weak<dyn IndexNode>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct InnerPageCache {
|
||||
pages: HashMap<usize, Arc<Page>>,
|
||||
page_cache_ref: Weak<PageCache>,
|
||||
}
|
||||
|
||||
impl InnerPageCache {
|
||||
pub fn new(page_cache_ref: Weak<PageCache>) -> InnerPageCache {
|
||||
Self {
|
||||
pages: HashMap::new(),
|
||||
page_cache_ref,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_page(&mut self, offset: usize, page: &Arc<Page>) {
|
||||
self.pages.insert(offset, page.clone());
|
||||
}
|
||||
|
||||
pub fn get_page(&self, offset: usize) -> Option<Arc<Page>> {
|
||||
self.pages.get(&offset).cloned()
|
||||
}
|
||||
|
||||
pub fn remove_page(&mut self, offset: usize) -> Option<Arc<Page>> {
|
||||
self.pages.remove(&offset)
|
||||
}
|
||||
|
||||
fn create_pages(&mut self, start_page_index: usize, buf: &[u8]) -> Result<(), SystemError> {
|
||||
assert!(buf.len() % MMArch::PAGE_SIZE == 0);
|
||||
|
||||
let page_num = buf.len() / MMArch::PAGE_SIZE;
|
||||
|
||||
let len = buf.len();
|
||||
if len == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
|
||||
for i in 0..page_num {
|
||||
let buf_offset = i * MMArch::PAGE_SIZE;
|
||||
let page_index = start_page_index + i;
|
||||
|
||||
let page = page_manager_guard.create_one_page(
|
||||
PageType::File(FileMapInfo {
|
||||
page_cache: self
|
||||
.page_cache_ref
|
||||
.upgrade()
|
||||
.expect("failed to get self_arc of pagecache"),
|
||||
index: page_index,
|
||||
}),
|
||||
PageFlags::PG_LRU,
|
||||
&mut LockedFrameAllocator,
|
||||
)?;
|
||||
|
||||
let mut page_guard = page.write_irqsave();
|
||||
unsafe {
|
||||
page_guard.copy_from_slice(&buf[buf_offset..buf_offset + MMArch::PAGE_SIZE]);
|
||||
}
|
||||
|
||||
self.add_page(page_index, &page);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// 从PageCache中读取数据。
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `offset` 偏移量
|
||||
/// - `buf` 缓冲区
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// - `Ok(usize)` 成功读取的长度
|
||||
/// - `Err(SystemError)` 失败返回错误码
|
||||
pub fn read(&mut self, offset: usize, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
let inode = self
|
||||
.page_cache_ref
|
||||
.upgrade()
|
||||
.unwrap()
|
||||
.inode
|
||||
.upgrade()
|
||||
.unwrap();
|
||||
let file_size = inode.metadata().unwrap().size;
|
||||
|
||||
let len = if offset < file_size as usize {
|
||||
core::cmp::min(file_size as usize, offset + buf.len()) - offset
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
if len == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let mut not_exist = Vec::new();
|
||||
|
||||
let start_page_index = offset >> MMArch::PAGE_SHIFT;
|
||||
let page_num = (page_align_up(offset + len) >> MMArch::PAGE_SHIFT) - start_page_index;
|
||||
|
||||
let mut buf_offset = 0;
|
||||
let mut ret = 0;
|
||||
for i in 0..page_num {
|
||||
let page_index = start_page_index + i;
|
||||
|
||||
// 第一个页可能需要计算页内偏移
|
||||
let page_offset = if i == 0 {
|
||||
offset % MMArch::PAGE_SIZE
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
// 第一个页和最后一个页可能不满
|
||||
let sub_len = if i == 0 {
|
||||
min(len, MMArch::PAGE_SIZE - page_offset)
|
||||
} else if i == page_num - 1 {
|
||||
(offset + len - 1) % MMArch::PAGE_SIZE + 1
|
||||
} else {
|
||||
MMArch::PAGE_SIZE
|
||||
};
|
||||
|
||||
if let Some(page) = self.get_page(page_index) {
|
||||
let sub_buf = &mut buf[buf_offset..(buf_offset + sub_len)];
|
||||
unsafe {
|
||||
sub_buf.copy_from_slice(
|
||||
&page.read_irqsave().as_slice()[page_offset..page_offset + sub_len],
|
||||
);
|
||||
}
|
||||
ret += sub_len;
|
||||
} else if let Some((index, count)) = not_exist.last_mut() {
|
||||
if *index + *count == page_index {
|
||||
*count += 1;
|
||||
} else {
|
||||
not_exist.push((page_index, 1));
|
||||
}
|
||||
} else {
|
||||
not_exist.push((page_index, 1));
|
||||
}
|
||||
|
||||
buf_offset += sub_len;
|
||||
}
|
||||
|
||||
for (page_index, count) in not_exist {
|
||||
// TODO 这里使用buffer避免多次读取磁盘,将来引入异步IO直接写入页面,减少内存开销和拷贝
|
||||
let mut page_buf = vec![0u8; MMArch::PAGE_SIZE * count];
|
||||
inode.read_sync(page_index * MMArch::PAGE_SIZE, page_buf.as_mut())?;
|
||||
|
||||
self.create_pages(page_index, page_buf.as_mut())?;
|
||||
|
||||
// 实际要拷贝的内容在文件中的偏移量
|
||||
let copy_offset = core::cmp::max(page_index * MMArch::PAGE_SIZE, offset);
|
||||
// 实际要拷贝的内容的长度
|
||||
let copy_len = core::cmp::min((page_index + count) * MMArch::PAGE_SIZE, offset + len)
|
||||
- copy_offset;
|
||||
|
||||
let page_buf_offset = if page_index * MMArch::PAGE_SIZE < copy_offset {
|
||||
copy_offset - page_index * MMArch::PAGE_SIZE
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let buf_offset = copy_offset.saturating_sub(offset);
|
||||
|
||||
buf[buf_offset..buf_offset + copy_len]
|
||||
.copy_from_slice(&page_buf[page_buf_offset..page_buf_offset + copy_len]);
|
||||
|
||||
ret += copy_len;
|
||||
|
||||
// log::debug!("page_offset:{page_offset}, count:{count}");
|
||||
// log::debug!("copy_offset:{copy_offset}, copy_len:{copy_len}");
|
||||
// log::debug!("buf_offset:{buf_offset}, page_buf_offset:{page_buf_offset}");
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
/// 向PageCache中写入数据。
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `offset` 偏移量
|
||||
/// - `buf` 缓冲区
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// - `Ok(usize)` 成功读取的长度
|
||||
/// - `Err(SystemError)` 失败返回错误码
|
||||
pub fn write(&mut self, offset: usize, buf: &[u8]) -> Result<usize, SystemError> {
|
||||
let len = buf.len();
|
||||
if len == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
// log::debug!("offset:{offset}, len:{len}");
|
||||
|
||||
let start_page_index = offset >> MMArch::PAGE_SHIFT;
|
||||
let page_num = (page_align_up(offset + len) >> MMArch::PAGE_SHIFT) - start_page_index;
|
||||
|
||||
let mut buf_offset = 0;
|
||||
let mut ret = 0;
|
||||
|
||||
for i in 0..page_num {
|
||||
let page_index = start_page_index + i;
|
||||
|
||||
// 第一个页可能需要计算页内偏移
|
||||
let page_offset = if i == 0 {
|
||||
offset % MMArch::PAGE_SIZE
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
// 第一个页和最后一个页可能不满
|
||||
let sub_len = if i == 0 {
|
||||
min(len, MMArch::PAGE_SIZE - page_offset)
|
||||
} else if i == page_num - 1 {
|
||||
(offset + len - 1) % MMArch::PAGE_SIZE + 1
|
||||
} else {
|
||||
MMArch::PAGE_SIZE
|
||||
};
|
||||
|
||||
let mut page = self.get_page(page_index);
|
||||
|
||||
if page.is_none() {
|
||||
let page_buf = vec![0u8; MMArch::PAGE_SIZE];
|
||||
self.create_pages(page_index, &page_buf)?;
|
||||
page = self.get_page(page_index);
|
||||
}
|
||||
|
||||
if let Some(page) = page {
|
||||
let sub_buf = &buf[buf_offset..(buf_offset + sub_len)];
|
||||
let mut page_guard = page.write_irqsave();
|
||||
unsafe {
|
||||
page_guard.as_slice_mut()[page_offset..page_offset + sub_len]
|
||||
.copy_from_slice(sub_buf);
|
||||
}
|
||||
page_guard.add_flags(PageFlags::PG_DIRTY);
|
||||
|
||||
ret += sub_len;
|
||||
|
||||
// log::debug!(
|
||||
// "page_offset:{page_offset}, buf_offset:{buf_offset}, sub_len:{sub_len}"
|
||||
// );
|
||||
} else {
|
||||
return Err(SystemError::EIO);
|
||||
};
|
||||
|
||||
buf_offset += sub_len;
|
||||
}
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
pub fn resize(&mut self, len: usize) -> Result<(), SystemError> {
|
||||
let page_num = page_align_up(len) / MMArch::PAGE_SIZE;
|
||||
|
||||
let mut reclaimer = page_reclaimer_lock_irqsave();
|
||||
for (_i, page) in self.pages.drain_filter(|index, _page| *index >= page_num) {
|
||||
let _ = reclaimer.remove_page(&page.phys_address());
|
||||
}
|
||||
|
||||
if page_num > 0 {
|
||||
let last_page_index = page_num - 1;
|
||||
let last_len = len - last_page_index * MMArch::PAGE_SIZE;
|
||||
if let Some(page) = self.get_page(last_page_index) {
|
||||
unsafe {
|
||||
page.write_irqsave().truncate(last_len);
|
||||
};
|
||||
} else {
|
||||
return Err(SystemError::EIO);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for InnerPageCache {
|
||||
fn drop(&mut self) {
|
||||
log::debug!("page cache drop");
|
||||
let mut page_manager = page_manager_lock_irqsave();
|
||||
for page in self.pages.values() {
|
||||
page_manager.remove_page(&page.phys_address());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PageCache {
|
||||
pub fn new(inode: Option<Weak<dyn IndexNode>>) -> Arc<PageCache> {
|
||||
Arc::new_cyclic(|weak| Self {
|
||||
inner: SpinLock::new(InnerPageCache::new(weak.clone())),
|
||||
inode: {
|
||||
let v: Lazy<Weak<dyn IndexNode>> = Lazy::new();
|
||||
if let Some(inode) = inode {
|
||||
v.init(inode);
|
||||
}
|
||||
v
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
pub fn inode(&self) -> Option<Weak<dyn IndexNode>> {
|
||||
self.inode.try_get().cloned()
|
||||
}
|
||||
|
||||
pub fn set_inode(&self, inode: Weak<dyn IndexNode>) -> Result<(), SystemError> {
|
||||
if self.inode.initialized() {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
self.inode.init(inode);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn lock_irqsave(&self) -> SpinLockGuard<InnerPageCache> {
|
||||
self.inner.lock_irqsave()
|
||||
}
|
||||
}
|
@ -5,16 +5,13 @@ use alloc::{
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
use kdepends::xarray::XArray;
|
||||
use log::error;
|
||||
use system_error::SystemError;
|
||||
|
||||
use super::{Dirent, FileType, IndexNode, InodeId, Metadata, SpecialNodeData};
|
||||
use crate::filesystem::eventfd::EventFdInode;
|
||||
use crate::libs::lazy_init::Lazy;
|
||||
use crate::perf::PerfEventInode;
|
||||
use crate::{
|
||||
arch::MMArch,
|
||||
driver::{
|
||||
base::{block::SeekFrom, device::DevicePrivateData},
|
||||
tty::tty_device::TtyFilePrivateData,
|
||||
@ -22,7 +19,6 @@ use crate::{
|
||||
filesystem::procfs::ProcfsFilePrivateData,
|
||||
ipc::pipe::{LockedPipeInode, PipeFsPrivateData},
|
||||
libs::{rwlock::RwLock, spinlock::SpinLock},
|
||||
mm::{page::Page, MemoryManagementArch},
|
||||
net::{
|
||||
event_poll::{EPollItem, EPollPrivateData, EventPoll},
|
||||
socket::SocketInode,
|
||||
@ -124,75 +120,6 @@ impl FileMode {
|
||||
}
|
||||
}
|
||||
|
||||
/// 页面缓存
|
||||
pub struct PageCache {
|
||||
xarray: SpinLock<XArray<Arc<Page>>>,
|
||||
inode: Lazy<Weak<dyn IndexNode>>,
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for PageCache {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_struct("PageCache")
|
||||
.field(
|
||||
"xarray",
|
||||
&self
|
||||
.xarray
|
||||
.lock()
|
||||
.range(0..((MMArch::PAGE_ADDRESS_SIZE >> MMArch::PAGE_SHIFT) as u64))
|
||||
.map(|(_, r)| (*r).clone())
|
||||
.collect::<Vec<Arc<Page>>>(),
|
||||
)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl PageCache {
|
||||
pub fn new(inode: Option<Weak<dyn IndexNode>>) -> Arc<PageCache> {
|
||||
let page_cache = Self {
|
||||
xarray: SpinLock::new(XArray::new()),
|
||||
inode: {
|
||||
let v: Lazy<Weak<dyn IndexNode>> = Lazy::new();
|
||||
if let Some(inode) = inode {
|
||||
v.init(inode);
|
||||
}
|
||||
v
|
||||
},
|
||||
};
|
||||
Arc::new(page_cache)
|
||||
}
|
||||
|
||||
pub fn inode(&self) -> Option<Weak<dyn IndexNode>> {
|
||||
self.inode.try_get().cloned()
|
||||
}
|
||||
|
||||
pub fn add_page(&self, offset: usize, page: &Arc<Page>) {
|
||||
let mut guard = self.xarray.lock();
|
||||
let mut cursor = guard.cursor_mut(offset as u64);
|
||||
cursor.store(page.clone());
|
||||
}
|
||||
|
||||
pub fn get_page(&self, offset: usize) -> Option<Arc<Page>> {
|
||||
let mut guard = self.xarray.lock();
|
||||
let mut cursor = guard.cursor_mut(offset as u64);
|
||||
let page = cursor.load().map(|r| (*r).clone());
|
||||
page
|
||||
}
|
||||
|
||||
pub fn remove_page(&self, offset: usize) {
|
||||
let mut guard = self.xarray.lock();
|
||||
let mut cursor = guard.cursor_mut(offset as u64);
|
||||
cursor.remove();
|
||||
}
|
||||
|
||||
pub fn set_inode(&self, inode: Weak<dyn IndexNode>) -> Result<(), SystemError> {
|
||||
if self.inode.initialized() {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
self.inode.init(inode);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 抽象文件结构体
|
||||
#[derive(Debug)]
|
||||
pub struct File {
|
||||
@ -238,13 +165,16 @@ impl File {
|
||||
return Ok(f);
|
||||
}
|
||||
|
||||
/// @brief 从文件中读取指定的字节数到buffer中
|
||||
/// ## 从文件中读取指定的字节数到buffer中
|
||||
///
|
||||
/// @param len 要读取的字节数
|
||||
/// @param buf 目标buffer
|
||||
/// ### 参数
|
||||
/// - `len`: 要读取的字节数
|
||||
/// - `buf`: 缓冲区
|
||||
/// - `read_direct`: 忽略缓存,直接读取磁盘
|
||||
///
|
||||
/// @return Ok(usize) 成功读取的字节数
|
||||
/// @return Err(SystemError) 错误码
|
||||
/// ### 返回值
|
||||
/// - `Ok(usize)`: 成功读取的字节数
|
||||
/// - `Err(SystemError)`: 错误码
|
||||
pub fn read(&self, len: usize, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
self.do_read(
|
||||
self.offset.load(core::sync::atomic::Ordering::SeqCst),
|
||||
@ -254,13 +184,16 @@ impl File {
|
||||
)
|
||||
}
|
||||
|
||||
/// @brief 从buffer向文件写入指定的字节数的数据
|
||||
/// ## 从buffer向文件写入指定的字节数的数据
|
||||
///
|
||||
/// @param len 要写入的字节数
|
||||
/// @param buf 源数据buffer
|
||||
/// ### 参数
|
||||
/// - `offset`: 文件偏移量
|
||||
/// - `len`: 要写入的字节数
|
||||
/// - `buf`: 写入缓冲区
|
||||
///
|
||||
/// @return Ok(usize) 成功写入的字节数
|
||||
/// @return Err(SystemError) 错误码
|
||||
/// ### 返回值
|
||||
/// - `Ok(usize)`: 成功写入的字节数
|
||||
/// - `Err(SystemError)`: 错误码
|
||||
pub fn write(&self, len: usize, buf: &[u8]) -> Result<usize, SystemError> {
|
||||
self.do_write(
|
||||
self.offset.load(core::sync::atomic::Ordering::SeqCst),
|
||||
@ -309,9 +242,13 @@ impl File {
|
||||
return Err(SystemError::ENOBUFS);
|
||||
}
|
||||
|
||||
let len = self
|
||||
.inode
|
||||
.read_at(offset, len, buf, self.private_data.lock())?;
|
||||
let len = if self.mode().contains(FileMode::O_DIRECT) {
|
||||
self.inode
|
||||
.read_direct(offset, len, buf, self.private_data.lock())
|
||||
} else {
|
||||
self.inode
|
||||
.read_at(offset, len, buf, self.private_data.lock())
|
||||
}?;
|
||||
|
||||
if update_offset {
|
||||
self.offset
|
||||
|
@ -24,14 +24,11 @@ use crate::{
|
||||
time::PosixTimeSpec,
|
||||
};
|
||||
|
||||
use self::{
|
||||
core::generate_inode_id,
|
||||
file::{FileMode, PageCache},
|
||||
syscall::ModeType,
|
||||
utils::DName,
|
||||
};
|
||||
use self::{core::generate_inode_id, file::FileMode, syscall::ModeType, utils::DName};
|
||||
pub use self::{core::ROOT_INODE, file::FilePrivateData, mount::MountFS};
|
||||
|
||||
use super::page_cache::PageCache;
|
||||
|
||||
/// vfs容许的最大的路径名称长度
|
||||
pub const MAX_PATHLEN: usize = 1024;
|
||||
|
||||
@ -128,6 +125,15 @@ pub trait IndexNode: Any + Sync + Send + Debug + CastFromSync {
|
||||
fn mmap(&self, _start: usize, _len: usize, _offset: usize) -> Result<(), SystemError> {
|
||||
return Err(SystemError::ENOSYS);
|
||||
}
|
||||
|
||||
fn read_sync(&self, _offset: usize, _buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
return Err(SystemError::ENOSYS);
|
||||
}
|
||||
|
||||
fn write_sync(&self, _offset: usize, _buf: &[u8]) -> Result<usize, SystemError> {
|
||||
return Err(SystemError::ENOSYS);
|
||||
}
|
||||
|
||||
/// @brief 打开文件
|
||||
///
|
||||
/// @return 成功:Ok()
|
||||
@ -184,6 +190,52 @@ pub trait IndexNode: Any + Sync + Send + Debug + CastFromSync {
|
||||
_data: SpinLockGuard<FilePrivateData>,
|
||||
) -> Result<usize, SystemError>;
|
||||
|
||||
/// # 在inode的指定偏移量开始,读取指定大小的数据,忽略PageCache
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `offset`: 起始位置在Inode中的偏移量
|
||||
/// - `len`: 要读取的字节数
|
||||
/// - `buf`: 缓冲区
|
||||
/// - `data`: 各文件系统系统所需私有信息
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// - `Ok(usize)``: Ok(读取的字节数)
|
||||
/// - `Err(SystemError)``: Err(Posix错误码)
|
||||
fn read_direct(
|
||||
&self,
|
||||
_offset: usize,
|
||||
_len: usize,
|
||||
_buf: &mut [u8],
|
||||
_data: SpinLockGuard<FilePrivateData>,
|
||||
) -> Result<usize, SystemError> {
|
||||
return Err(SystemError::ENOSYS);
|
||||
}
|
||||
|
||||
/// # 在inode的指定偏移量开始,写入指定大小的数据,忽略PageCache
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `offset`: 起始位置在Inode中的偏移量
|
||||
/// - `len`: 要读取的字节数
|
||||
/// - `buf`: 缓冲区
|
||||
/// - `data`: 各文件系统系统所需私有信息
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// - `Ok(usize)``: Ok(读取的字节数)
|
||||
/// - `Err(SystemError)``: Err(Posix错误码)
|
||||
fn write_direct(
|
||||
&self,
|
||||
_offset: usize,
|
||||
_len: usize,
|
||||
_buf: &[u8],
|
||||
_data: SpinLockGuard<FilePrivateData>,
|
||||
) -> Result<usize, SystemError> {
|
||||
return Err(SystemError::ENOSYS);
|
||||
}
|
||||
|
||||
/// @brief 获取当前inode的状态。
|
||||
///
|
||||
/// @return PollStatus结构体
|
||||
|
@ -14,7 +14,7 @@ use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
driver::base::device::device_number::DeviceNumber,
|
||||
filesystem::vfs::ROOT_INODE,
|
||||
filesystem::{page_cache::PageCache, vfs::ROOT_INODE},
|
||||
libs::{
|
||||
casting::DowncastArc,
|
||||
rwlock::RwLock,
|
||||
@ -24,10 +24,8 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
file::{FileMode, PageCache},
|
||||
syscall::ModeType,
|
||||
utils::DName,
|
||||
FilePrivateData, FileSystem, FileType, IndexNode, InodeId, Magic, SuperBlock,
|
||||
file::FileMode, syscall::ModeType, utils::DName, FilePrivateData, FileSystem, FileType,
|
||||
IndexNode, InodeId, Magic, SuperBlock,
|
||||
};
|
||||
|
||||
const MOUNTFS_BLOCK_SIZE: u64 = 512;
|
||||
@ -296,6 +294,26 @@ impl IndexNode for MountFSInode {
|
||||
return self.inner_inode.write_at(offset, len, buf, data);
|
||||
}
|
||||
|
||||
fn read_direct(
|
||||
&self,
|
||||
offset: usize,
|
||||
len: usize,
|
||||
buf: &mut [u8],
|
||||
data: SpinLockGuard<FilePrivateData>,
|
||||
) -> Result<usize, SystemError> {
|
||||
self.inner_inode.read_direct(offset, len, buf, data)
|
||||
}
|
||||
|
||||
fn write_direct(
|
||||
&self,
|
||||
offset: usize,
|
||||
len: usize,
|
||||
buf: &[u8],
|
||||
data: SpinLockGuard<FilePrivateData>,
|
||||
) -> Result<usize, SystemError> {
|
||||
self.inner_inode.write_direct(offset, len, buf, data)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fs(&self) -> Arc<dyn FileSystem> {
|
||||
return self.mount_fs.clone();
|
||||
|
@ -7,16 +7,15 @@ use crate::{
|
||||
},
|
||||
mm::{
|
||||
allocator::page_frame::{FrameAllocator, PageFrameCount, PhysPageFrame},
|
||||
page::{page_manager_lock_irqsave, Page},
|
||||
page::{page_manager_lock_irqsave, PageFlags, PageType},
|
||||
PhysAddr,
|
||||
},
|
||||
process::{Pid, ProcessManager},
|
||||
syscall::user_access::{UserBufferReader, UserBufferWriter},
|
||||
time::PosixTimeSpec,
|
||||
};
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use hashbrown::HashMap;
|
||||
use ida::IdAllocator;
|
||||
use log::info;
|
||||
use num::ToPrimitive;
|
||||
@ -159,21 +158,16 @@ impl ShmManager {
|
||||
|
||||
// 分配共享内存页面
|
||||
let page_count = PageFrameCount::from_bytes(page_align_up(size)).unwrap();
|
||||
let phys_page =
|
||||
unsafe { LockedFrameAllocator.allocate(page_count) }.ok_or(SystemError::EINVAL)?;
|
||||
// 创建共享内存page,并添加到PAGE_MANAGER中
|
||||
let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
let mut cur_phys = PhysPageFrame::new(phys_page.0);
|
||||
for _ in 0..page_count.data() {
|
||||
let page = Arc::new(Page::new(true, cur_phys.phys_address()));
|
||||
page.write_irqsave().set_shm_id(shm_id);
|
||||
let paddr = cur_phys.phys_address();
|
||||
page_manager_guard.insert(paddr, &page);
|
||||
cur_phys = cur_phys.next();
|
||||
}
|
||||
let (paddr, _page) = page_manager_guard.create_pages(
|
||||
PageType::Shm(shm_id),
|
||||
PageFlags::PG_UNEVICTABLE,
|
||||
&mut LockedFrameAllocator,
|
||||
page_count,
|
||||
)?;
|
||||
|
||||
// 创建共享内存信息结构体
|
||||
let paddr = phys_page.0;
|
||||
let kern_ipc_perm = KernIpcPerm {
|
||||
id: shm_id,
|
||||
key,
|
||||
@ -323,9 +317,10 @@ impl ShmManager {
|
||||
let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
if map_count > 0 {
|
||||
// 设置共享内存物理页当映射计数等于0时可被回收
|
||||
// TODO 后续需要加入到lru中
|
||||
for _ in 0..count.data() {
|
||||
let page = page_manager_guard.get_unwrap(&cur_phys.phys_address());
|
||||
page.write_irqsave().set_dealloc_when_zero(true);
|
||||
page.write_irqsave().remove_flags(PageFlags::PG_UNEVICTABLE);
|
||||
|
||||
cur_phys = cur_phys.next();
|
||||
}
|
||||
@ -375,6 +370,8 @@ pub struct KernelShm {
|
||||
shm_start_paddr: PhysAddr,
|
||||
/// 共享内存大小(bytes),注意是用户指定的大小(未经过页面对齐)
|
||||
shm_size: usize,
|
||||
/// 映射计数
|
||||
map_count: usize,
|
||||
/// 最后一次连接的时间
|
||||
shm_atim: PosixTimeSpec,
|
||||
/// 最后一次断开连接的时间
|
||||
@ -394,6 +391,7 @@ impl KernelShm {
|
||||
kern_ipc_perm,
|
||||
shm_start_paddr,
|
||||
shm_size,
|
||||
map_count: 0,
|
||||
shm_atim: PosixTimeSpec::new(0, 0),
|
||||
shm_dtim: PosixTimeSpec::new(0, 0),
|
||||
shm_ctim: PosixTimeSpec::now(),
|
||||
@ -436,26 +434,7 @@ impl KernelShm {
|
||||
|
||||
/// 共享内存段的映射计数(有多少个不同的VMA映射)
|
||||
pub fn map_count(&self) -> usize {
|
||||
let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
let mut id_set: HashSet<usize> = HashSet::new();
|
||||
let mut cur_phys = PhysPageFrame::new(self.shm_start_paddr);
|
||||
let page_count = PageFrameCount::from_bytes(page_align_up(self.shm_size)).unwrap();
|
||||
|
||||
for _ in 0..page_count.data() {
|
||||
let page = page_manager_guard.get(&cur_phys.phys_address()).unwrap();
|
||||
id_set.extend(
|
||||
page.read_irqsave()
|
||||
.anon_vma()
|
||||
.iter()
|
||||
.map(|vma| vma.id())
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
cur_phys = cur_phys.next();
|
||||
}
|
||||
|
||||
// 由于LockedVMA的id是独一无二的,因此有多少个不同的id,就代表着有多少个不同的VMA映射到共享内存段
|
||||
return id_set.len();
|
||||
self.map_count
|
||||
}
|
||||
|
||||
pub fn copy_from(&mut self, shm_id_ds: PosixShmIdDs) {
|
||||
@ -474,6 +453,19 @@ impl KernelShm {
|
||||
|
||||
self.update_ctim();
|
||||
}
|
||||
|
||||
pub fn mode(&self) -> &ShmFlags {
|
||||
&self.kern_ipc_perm.mode
|
||||
}
|
||||
|
||||
pub fn increase_count(&mut self) {
|
||||
self.map_count += 1;
|
||||
}
|
||||
|
||||
pub fn decrease_count(&mut self) {
|
||||
assert!(self.map_count > 0, "map_count is zero");
|
||||
self.map_count -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// 共享内存权限信息
|
||||
|
@ -16,8 +16,7 @@ use crate::{
|
||||
FilePrivateData,
|
||||
},
|
||||
ipc::shm::{shm_manager_lock, IPC_PRIVATE},
|
||||
libs::align::page_align_up,
|
||||
libs::spinlock::SpinLock,
|
||||
libs::{align::page_align_up, spinlock::SpinLock},
|
||||
mm::{
|
||||
allocator::page_frame::{PageFrameCount, PhysPageFrame, VirtPageFrame},
|
||||
page::{page_manager_lock_irqsave, EntryFlags, PageFlushAll},
|
||||
@ -405,6 +404,9 @@ impl Syscall {
|
||||
// 更新最后一次连接时间
|
||||
kernel_shm.update_atim();
|
||||
|
||||
// 映射计数增加
|
||||
kernel_shm.increase_count();
|
||||
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
@ -433,29 +435,6 @@ impl Syscall {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
// 获取映射的物理地址
|
||||
let paddr = address_write_guard
|
||||
.user_mapper
|
||||
.utable
|
||||
.translate(vaddr)
|
||||
.ok_or(SystemError::EINVAL)?
|
||||
.0;
|
||||
|
||||
// 如果物理页的shm_id为None,代表不是共享页
|
||||
let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
let page = page_manager_guard.get(&paddr).ok_or(SystemError::EINVAL)?;
|
||||
let shm_id = page.read_irqsave().shm_id().ok_or(SystemError::EINVAL)?;
|
||||
drop(page_manager_guard);
|
||||
|
||||
// 获取对应共享页管理信息
|
||||
let mut shm_manager_guard = shm_manager_lock();
|
||||
let kernel_shm = shm_manager_guard
|
||||
.get_mut(&shm_id)
|
||||
.ok_or(SystemError::EINVAL)?;
|
||||
// 更新最后一次断开连接时间
|
||||
kernel_shm.update_dtim();
|
||||
drop(shm_manager_guard);
|
||||
|
||||
// 取消映射
|
||||
let flusher: PageFlushAll<MMArch> = PageFlushAll::new();
|
||||
vma.unmap(&mut address_write_guard.user_mapper.utable, flusher);
|
||||
|
@ -5,8 +5,6 @@ use core::{
|
||||
|
||||
use crate::{
|
||||
arch::{mm::LockedFrameAllocator, MMArch},
|
||||
ipc::shm::shm_manager_lock,
|
||||
libs::spinlock::SpinLockGuard,
|
||||
mm::{MemoryManagementArch, PhysAddr, VirtAddr},
|
||||
};
|
||||
|
||||
@ -173,6 +171,8 @@ impl Iterator for VirtPageFrameIter {
|
||||
pub struct PageFrameCount(usize);
|
||||
|
||||
impl PageFrameCount {
|
||||
pub const ONE: PageFrameCount = PageFrameCount(1);
|
||||
|
||||
// @brief 初始化PageFrameCount
|
||||
pub const fn new(count: usize) -> Self {
|
||||
return Self(count);
|
||||
@ -355,30 +355,8 @@ pub unsafe fn allocate_page_frames(count: PageFrameCount) -> Option<(PhysAddr, P
|
||||
///
|
||||
/// @param frame 要释放的第一个页帧
|
||||
/// @param count 要释放的页帧数量 (必须是2的n次幂)
|
||||
pub unsafe fn deallocate_page_frames(
|
||||
frame: PhysPageFrame,
|
||||
count: PageFrameCount,
|
||||
page_manager_guard: &mut SpinLockGuard<'_, crate::mm::page::PageManager>,
|
||||
) {
|
||||
pub unsafe fn deallocate_page_frames(frame: PhysPageFrame, count: PageFrameCount) {
|
||||
unsafe {
|
||||
LockedFrameAllocator.free(frame.phys_address(), count);
|
||||
}
|
||||
|
||||
let mut frame = frame;
|
||||
for _ in 0..count.data() {
|
||||
let paddr = frame.phys_address();
|
||||
let page = page_manager_guard.get(&paddr);
|
||||
|
||||
if let Some(page) = page {
|
||||
// 如果page是共享页,将其共享页信息从SHM_MANAGER中删去
|
||||
let page_guard = page.read_irqsave();
|
||||
if page_guard.shared() {
|
||||
shm_manager_lock().free_id(&page_guard.shm_id().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
// 将已回收的物理页面对应的Page从PAGE_MANAGER中删去
|
||||
page_manager_guard.remove_page(&paddr);
|
||||
frame = frame.next();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ use crate::mm::MemoryManagementArch;
|
||||
|
||||
use super::{
|
||||
allocator::page_frame::FrameAllocator,
|
||||
page::{page_reclaimer_lock_irqsave, Page, PageFlags},
|
||||
page::{FileMapInfo, Page, PageFlags, PageType},
|
||||
};
|
||||
|
||||
bitflags! {
|
||||
@ -55,7 +55,7 @@ pub struct PageFaultMessage<'a> {
|
||||
flags: FaultFlags,
|
||||
/// 页表映射器
|
||||
mapper: &'a mut PageMapper,
|
||||
/// 缺页的文件页在文件中的偏移量
|
||||
/// 缺页的文件页在文件中的偏移页号
|
||||
file_pgoff: Option<usize>,
|
||||
/// 缺页对应PageCache中的文件页
|
||||
page: Option<Arc<Page>>,
|
||||
@ -308,32 +308,14 @@ impl PageFaultHandler {
|
||||
let cache_page = pfm.page.clone().unwrap();
|
||||
let mapper = &mut pfm.mapper;
|
||||
|
||||
let cow_page_phys = mapper.allocator_mut().allocate_one();
|
||||
if cow_page_phys.is_none() {
|
||||
let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
if let Ok(page) =
|
||||
page_manager_guard.copy_page(&cache_page.phys_address(), mapper.allocator_mut())
|
||||
{
|
||||
pfm.cow_page = Some(page.clone());
|
||||
} else {
|
||||
return VmFaultReason::VM_FAULT_OOM;
|
||||
}
|
||||
let cow_page_phys = cow_page_phys.unwrap();
|
||||
|
||||
let cow_page = Arc::new(Page::new(false, cow_page_phys));
|
||||
pfm.cow_page = Some(cow_page.clone());
|
||||
|
||||
//复制PageCache内容到新的页内
|
||||
let new_frame = MMArch::phys_2_virt(cow_page_phys).unwrap();
|
||||
(new_frame.data() as *mut u8).copy_from_nonoverlapping(
|
||||
MMArch::phys_2_virt(cache_page.read_irqsave().phys_address())
|
||||
.unwrap()
|
||||
.data() as *mut u8,
|
||||
MMArch::PAGE_SIZE,
|
||||
);
|
||||
|
||||
let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
|
||||
// 新页加入页管理器中
|
||||
page_manager_guard.insert(cow_page_phys, &cow_page);
|
||||
cow_page.write_irqsave().set_page_cache_index(
|
||||
cache_page.read_irqsave().page_cache(),
|
||||
cache_page.read_irqsave().index(),
|
||||
);
|
||||
|
||||
ret = ret.union(Self::finish_fault(pfm));
|
||||
|
||||
@ -608,10 +590,10 @@ impl PageFaultHandler {
|
||||
<< MMArch::PAGE_SHIFT);
|
||||
|
||||
for pgoff in start_pgoff..=end_pgoff {
|
||||
if let Some(page) = page_cache.get_page(pgoff) {
|
||||
if let Some(page) = page_cache.lock_irqsave().get_page(pgoff) {
|
||||
let page_guard = page.read_irqsave();
|
||||
if page_guard.flags().contains(PageFlags::PG_UPTODATE) {
|
||||
let phys = page_guard.phys_address();
|
||||
let phys = page.phys_address();
|
||||
|
||||
let address =
|
||||
VirtAddr::new(addr.data() + ((pgoff - start_pgoff) << MMArch::PAGE_SHIFT));
|
||||
@ -642,7 +624,7 @@ impl PageFaultHandler {
|
||||
let mapper = &mut pfm.mapper;
|
||||
let mut ret = VmFaultReason::empty();
|
||||
|
||||
if let Some(page) = page_cache.get_page(file_pgoff) {
|
||||
if let Some(page) = page_cache.lock_irqsave().get_page(file_pgoff) {
|
||||
// TODO 异步从磁盘中预读页面进PageCache
|
||||
|
||||
// 直接将PageCache中的页面作为要映射的页面
|
||||
@ -669,16 +651,19 @@ impl PageFaultHandler {
|
||||
)
|
||||
.expect("failed to read file to create pagecache page");
|
||||
|
||||
let page = Arc::new(Page::new(true, new_cache_page));
|
||||
let page = page_manager_lock_irqsave()
|
||||
.create_one_page(
|
||||
PageType::File(FileMapInfo {
|
||||
page_cache: page_cache.clone(),
|
||||
index: file_pgoff,
|
||||
}),
|
||||
PageFlags::PG_LRU,
|
||||
allocator,
|
||||
)
|
||||
.expect("failed to create page");
|
||||
pfm.page = Some(page.clone());
|
||||
|
||||
page.write_irqsave().add_flags(PageFlags::PG_LRU);
|
||||
page_manager_lock_irqsave().insert(new_cache_page, &page);
|
||||
page_reclaimer_lock_irqsave().insert_page(new_cache_page, &page);
|
||||
page_cache.add_page(file_pgoff, &page);
|
||||
|
||||
page.write_irqsave()
|
||||
.set_page_cache_index(Some(page_cache), Some(file_pgoff));
|
||||
page_cache.lock_irqsave().add_page(file_pgoff, &page);
|
||||
}
|
||||
ret
|
||||
}
|
||||
@ -710,7 +695,7 @@ impl PageFaultHandler {
|
||||
cache_page.expect("no cache_page in PageFaultMessage")
|
||||
};
|
||||
|
||||
let page_phys = page_to_map.read_irqsave().phys_address();
|
||||
let page_phys = page_to_map.phys_address();
|
||||
|
||||
mapper.map_phys(address, page_phys, vma_guard.flags());
|
||||
page_to_map.write_irqsave().insert_vma(pfm.vma());
|
||||
|
@ -1,4 +1,4 @@
|
||||
use alloc::string::ToString;
|
||||
use alloc::{string::ToString, vec::Vec};
|
||||
use core::{
|
||||
fmt::{self, Debug, Error, Formatter},
|
||||
marker::PhantomData,
|
||||
@ -17,7 +17,7 @@ use lru::LruCache;
|
||||
use crate::{
|
||||
arch::{interrupt::ipi::send_ipi, mm::LockedFrameAllocator, MMArch},
|
||||
exception::ipi::{IpiKind, IpiTarget},
|
||||
filesystem::vfs::{file::PageCache, FilePrivateData},
|
||||
filesystem::{page_cache::PageCache, vfs::FilePrivateData},
|
||||
init::initcall::INITCALL_CORE,
|
||||
ipc::shm::ShmId,
|
||||
libs::{
|
||||
@ -29,7 +29,9 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
allocator::page_frame::{FrameAllocator, PageFrameCount},
|
||||
allocator::page_frame::{
|
||||
deallocate_page_frames, FrameAllocator, PageFrameCount, PhysPageFrame,
|
||||
},
|
||||
syscall::ProtFlags,
|
||||
ucontext::LockedVMA,
|
||||
MemoryManagementArch, PageTableKind, PhysAddr, VirtAddr,
|
||||
@ -74,6 +76,7 @@ impl PageManager {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn contains(&self, paddr: &PhysAddr) -> bool {
|
||||
self.phys2page.contains_key(paddr)
|
||||
}
|
||||
@ -91,13 +94,121 @@ impl PageManager {
|
||||
.clone()
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, paddr: PhysAddr, page: &Arc<Page>) {
|
||||
self.phys2page.insert(paddr, page.clone());
|
||||
fn insert(&mut self, page: &Arc<Page>) -> Result<Arc<Page>, SystemError> {
|
||||
let phys = page.phys_address();
|
||||
if !self.phys2page.contains_key(&phys) {
|
||||
self.phys2page.insert(phys, page.clone());
|
||||
Ok(page.clone())
|
||||
} else {
|
||||
log::error!("phys page: {phys:?} already exists.");
|
||||
Err(SystemError::EINVAL)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_page(&mut self, paddr: &PhysAddr) {
|
||||
self.phys2page.remove(paddr);
|
||||
}
|
||||
|
||||
/// # 创建一个新页面并加入管理器
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `shared`: 是否共享
|
||||
/// - `page_type`: 页面类型
|
||||
/// - `flags`: 页面标志
|
||||
/// - `allocator`: 物理页帧分配器
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// - `Ok(Arc<Page>)`: 新页面
|
||||
/// - `Err(SystemError)`: 错误码
|
||||
pub fn create_one_page(
|
||||
&mut self,
|
||||
page_type: PageType,
|
||||
flags: PageFlags,
|
||||
allocator: &mut dyn FrameAllocator,
|
||||
) -> Result<Arc<Page>, SystemError> {
|
||||
self.create_pages(page_type, flags, allocator, PageFrameCount::ONE)?
|
||||
.1
|
||||
.first()
|
||||
.ok_or(SystemError::ENOMEM)
|
||||
.cloned()
|
||||
}
|
||||
|
||||
/// # 创建新页面并加入管理器
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `shared`: 是否共享
|
||||
/// - `page_type`: 页面类型
|
||||
/// - `flags`: 页面标志
|
||||
/// - `allocator`: 物理页帧分配器
|
||||
/// - `count`: 页面数量
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// - `Ok((PhysAddr, Vec<Arc<Page>>))`: 页面起始物理地址,新页面集合
|
||||
/// - `Err(SystemError)`: 错误码
|
||||
pub fn create_pages(
|
||||
&mut self,
|
||||
page_type: PageType,
|
||||
flags: PageFlags,
|
||||
allocator: &mut dyn FrameAllocator,
|
||||
count: PageFrameCount,
|
||||
) -> Result<(PhysAddr, Vec<Arc<Page>>), SystemError> {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
let (start_paddr, count) = unsafe { allocator.allocate(count).ok_or(SystemError::ENOMEM)? };
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
unsafe {
|
||||
let vaddr = MMArch::phys_2_virt(start_paddr).unwrap();
|
||||
MMArch::write_bytes(vaddr, 0, MMArch::PAGE_SIZE * count.data());
|
||||
}
|
||||
|
||||
let mut cur_phys = PhysPageFrame::new(start_paddr);
|
||||
let mut ret: Vec<Arc<Page>> = Vec::new();
|
||||
for _ in 0..count.data() {
|
||||
let page = Page::new(cur_phys.phys_address(), page_type.clone(), flags);
|
||||
if let Err(e) = self.insert(&page) {
|
||||
for insert_page in ret {
|
||||
self.remove_page(&insert_page.read_irqsave().phys_addr);
|
||||
}
|
||||
return Err(e);
|
||||
}
|
||||
ret.push(page);
|
||||
cur_phys = cur_phys.next();
|
||||
}
|
||||
Ok((start_paddr, ret))
|
||||
}
|
||||
|
||||
/// # 拷贝管理器中原有页面并加入管理器,同时拷贝原页面内容
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `old_phys`: 原页面的物理地址
|
||||
/// - `allocator`: 物理页帧分配器
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// - `Ok(Arc<Page>)`: 新页面
|
||||
/// - `Err(SystemError)`: 错误码
|
||||
pub fn copy_page(
|
||||
&mut self,
|
||||
old_phys: &PhysAddr,
|
||||
allocator: &mut dyn FrameAllocator,
|
||||
) -> Result<Arc<Page>, SystemError> {
|
||||
let old_page = self.get(old_phys).ok_or(SystemError::EINVAL)?;
|
||||
let paddr = unsafe { allocator.allocate_one().ok_or(SystemError::ENOMEM)? };
|
||||
|
||||
assert!(!self.contains(&paddr), "phys page: {paddr:?} already exist");
|
||||
|
||||
let page = Page::copy(old_page.read_irqsave(), paddr)
|
||||
.inspect_err(|_| unsafe { allocator.free_one(paddr) })?;
|
||||
|
||||
self.insert(&page)?;
|
||||
|
||||
Ok(page)
|
||||
}
|
||||
}
|
||||
|
||||
pub static mut PAGE_RECLAIMER: Option<SpinLock<PageReclaimer>> = None;
|
||||
@ -150,7 +261,7 @@ fn page_reclaim_thread() -> i32 {
|
||||
page_reclaimer_lock_irqsave().flush_dirty_pages();
|
||||
// 休眠5秒
|
||||
// log::info!("sleep");
|
||||
let _ = nanosleep(PosixTimeSpec::new(5, 0));
|
||||
let _ = nanosleep(PosixTimeSpec::new(0, 500_000_000));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -180,28 +291,31 @@ impl PageReclaimer {
|
||||
self.lru.put(paddr, page.clone());
|
||||
}
|
||||
|
||||
pub fn remove_page(&mut self, paddr: &PhysAddr) -> Option<Arc<Page>> {
|
||||
self.lru.pop(paddr)
|
||||
}
|
||||
|
||||
/// lru链表缩减
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `count`: 需要缩减的页面数量
|
||||
pub fn shrink_list(&mut self, count: PageFrameCount) {
|
||||
for _ in 0..count.data() {
|
||||
let (paddr, page) = self.lru.pop_lru().expect("pagecache is empty");
|
||||
let page_cache = page.read_irqsave().page_cache().unwrap();
|
||||
for vma in page.read_irqsave().anon_vma() {
|
||||
let address_space = vma.lock_irqsave().address_space().unwrap();
|
||||
let address_space = address_space.upgrade().unwrap();
|
||||
let mut guard = address_space.write();
|
||||
let mapper = &mut guard.user_mapper.utable;
|
||||
let virt = vma.lock_irqsave().page_address(&page).unwrap();
|
||||
unsafe {
|
||||
mapper.unmap(virt, false).unwrap().flush();
|
||||
let (_, page) = self.lru.pop_lru().expect("pagecache is empty");
|
||||
let mut guard = page.write_irqsave();
|
||||
if let PageType::File(info) = guard.page_type().clone() {
|
||||
let page_cache = &info.page_cache;
|
||||
let page_index = info.index;
|
||||
let paddr = guard.phys_address();
|
||||
if guard.flags().contains(PageFlags::PG_DIRTY) {
|
||||
// 先回写脏页
|
||||
Self::page_writeback(&mut guard, true);
|
||||
}
|
||||
}
|
||||
page_cache.remove_page(page.read_irqsave().index().unwrap());
|
||||
page_manager_lock_irqsave().remove_page(&paddr);
|
||||
if page.read_irqsave().flags.contains(PageFlags::PG_DIRTY) {
|
||||
Self::page_writeback(&page, true);
|
||||
|
||||
// 删除页面
|
||||
page_cache.lock_irqsave().remove_page(page_index);
|
||||
page_manager_lock_irqsave().remove_page(&paddr);
|
||||
self.remove_page(&paddr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -215,24 +329,33 @@ impl PageReclaimer {
|
||||
/// 脏页回写函数
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `page`: 需要回写的脏页
|
||||
/// - `guard`: 需要回写的脏页
|
||||
/// - `unmap`: 是否取消映射
|
||||
///
|
||||
/// ## 返回值
|
||||
/// - VmFaultReason: 页面错误处理信息标志
|
||||
pub fn page_writeback(page: &Arc<Page>, unmap: bool) {
|
||||
if !unmap {
|
||||
page.write_irqsave().remove_flags(PageFlags::PG_DIRTY);
|
||||
}
|
||||
pub fn page_writeback(guard: &mut RwLockWriteGuard<InnerPage>, unmap: bool) {
|
||||
// log::debug!("page writeback: {:?}", guard.phys_addr);
|
||||
|
||||
for vma in page.read_irqsave().anon_vma() {
|
||||
let (page_cache, page_index) = match guard.page_type() {
|
||||
PageType::File(info) => (info.page_cache.clone(), info.index),
|
||||
_ => {
|
||||
log::warn!("try to writeback a non-file page");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let paddr = guard.phys_address();
|
||||
let inode = page_cache.inode().clone().unwrap().upgrade().unwrap();
|
||||
|
||||
for vma in guard.vma_set() {
|
||||
let address_space = vma.lock_irqsave().address_space().unwrap();
|
||||
let address_space = address_space.upgrade().unwrap();
|
||||
let mut guard = address_space.write();
|
||||
let mapper = &mut guard.user_mapper.utable;
|
||||
let virt = vma.lock_irqsave().page_address(page).unwrap();
|
||||
let virt = vma.lock_irqsave().page_address(page_index).unwrap();
|
||||
if unmap {
|
||||
unsafe {
|
||||
// 取消页表映射
|
||||
mapper.unmap(virt, false).unwrap().flush();
|
||||
}
|
||||
} else {
|
||||
@ -245,40 +368,44 @@ impl PageReclaimer {
|
||||
};
|
||||
}
|
||||
}
|
||||
let inode = page
|
||||
.read_irqsave()
|
||||
.page_cache
|
||||
.clone()
|
||||
.unwrap()
|
||||
.inode()
|
||||
.clone()
|
||||
.unwrap()
|
||||
.upgrade()
|
||||
.unwrap();
|
||||
|
||||
let len = if let Ok(metadata) = inode.metadata() {
|
||||
let size = metadata.size as usize;
|
||||
if size < page_index * MMArch::PAGE_SIZE {
|
||||
0
|
||||
} else {
|
||||
size - page_index * MMArch::PAGE_SIZE
|
||||
}
|
||||
} else {
|
||||
MMArch::PAGE_SIZE
|
||||
};
|
||||
|
||||
inode
|
||||
.write_at(
|
||||
page.read_irqsave().index().unwrap(),
|
||||
MMArch::PAGE_SIZE,
|
||||
.write_direct(
|
||||
page_index * MMArch::PAGE_SIZE,
|
||||
len,
|
||||
unsafe {
|
||||
core::slice::from_raw_parts(
|
||||
MMArch::phys_2_virt(page.read_irqsave().phys_addr)
|
||||
.unwrap()
|
||||
.data() as *mut u8,
|
||||
MMArch::PAGE_SIZE,
|
||||
MMArch::phys_2_virt(paddr).unwrap().data() as *mut u8,
|
||||
len,
|
||||
)
|
||||
},
|
||||
SpinLock::new(FilePrivateData::Unused).lock(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// 清除标记
|
||||
guard.remove_flags(PageFlags::PG_DIRTY);
|
||||
}
|
||||
|
||||
/// lru脏页刷新
|
||||
pub fn flush_dirty_pages(&self) {
|
||||
pub fn flush_dirty_pages(&mut self) {
|
||||
// log::info!("flush_dirty_pages");
|
||||
let iter = self.lru.iter();
|
||||
for (_, page) in iter {
|
||||
if page.read_irqsave().flags().contains(PageFlags::PG_DIRTY) {
|
||||
Self::page_writeback(page, false);
|
||||
for (_paddr, page) in iter {
|
||||
let mut guard = page.write_irqsave();
|
||||
if guard.flags().contains(PageFlags::PG_DIRTY) {
|
||||
Self::page_writeback(&mut guard, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -302,20 +429,76 @@ bitflags! {
|
||||
const PG_PRIVATE = 1 << 15;
|
||||
const PG_RECLAIM = 1 << 18;
|
||||
const PG_SWAPBACKED = 1 << 19;
|
||||
const PG_UNEVICTABLE = 1 << 20;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Page {
|
||||
inner: RwLock<InnerPage>,
|
||||
/// 页面所在物理地址
|
||||
phys_addr: PhysAddr,
|
||||
}
|
||||
|
||||
impl Page {
|
||||
pub fn new(shared: bool, phys_addr: PhysAddr) -> Self {
|
||||
let inner = InnerPage::new(shared, phys_addr);
|
||||
Self {
|
||||
/// # 创建新页面
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `shared`: 是否共享
|
||||
/// - `phys_addr`: 物理地址
|
||||
/// - `page_type`: 页面类型
|
||||
/// - `flags`: 页面标志
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// - `Arc<Page>`: 新页面
|
||||
fn new(phys_addr: PhysAddr, page_type: PageType, flags: PageFlags) -> Arc<Page> {
|
||||
let inner = InnerPage::new(phys_addr, page_type, flags);
|
||||
let page = Arc::new(Self {
|
||||
inner: RwLock::new(inner),
|
||||
phys_addr,
|
||||
});
|
||||
if page.read_irqsave().flags == PageFlags::PG_LRU {
|
||||
page_reclaimer_lock_irqsave().insert_page(phys_addr, &page);
|
||||
};
|
||||
page
|
||||
}
|
||||
|
||||
/// # 拷贝页面及内容
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `old_guard`: 源页面的读守卫
|
||||
/// - `new_phys`: 新页面的物理地址
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// - `Ok(Arc<Page>)`: 新页面
|
||||
/// - `Err(SystemError)`: 错误码
|
||||
fn copy(
|
||||
old_guard: RwLockReadGuard<InnerPage>,
|
||||
new_phys: PhysAddr,
|
||||
) -> Result<Arc<Page>, SystemError> {
|
||||
let page_type = old_guard.page_type().clone();
|
||||
let flags = *old_guard.flags();
|
||||
let inner = InnerPage::new(new_phys, page_type, flags);
|
||||
unsafe {
|
||||
let old_vaddr =
|
||||
MMArch::phys_2_virt(old_guard.phys_address()).ok_or(SystemError::EFAULT)?;
|
||||
let new_vaddr = MMArch::phys_2_virt(new_phys).ok_or(SystemError::EFAULT)?;
|
||||
(new_vaddr.data() as *mut u8)
|
||||
.copy_from_nonoverlapping(old_vaddr.data() as *mut u8, MMArch::PAGE_SIZE);
|
||||
}
|
||||
Ok(Arc::new(Self {
|
||||
inner: RwLock::new(inner),
|
||||
phys_addr: new_phys,
|
||||
}))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn phys_address(&self) -> PhysAddr {
|
||||
self.phys_addr
|
||||
}
|
||||
|
||||
pub fn read_irqsave(&self) -> RwLockReadGuard<InnerPage> {
|
||||
@ -330,107 +513,68 @@ impl Page {
|
||||
#[derive(Debug)]
|
||||
/// 物理页面信息
|
||||
pub struct InnerPage {
|
||||
/// 映射计数
|
||||
map_count: usize,
|
||||
/// 是否为共享页
|
||||
shared: bool,
|
||||
/// 映射计数为0时,是否可回收
|
||||
free_when_zero: bool,
|
||||
/// 共享页id(如果是共享页)
|
||||
shm_id: Option<ShmId>,
|
||||
/// 映射到当前page的VMA
|
||||
anon_vma: HashSet<Arc<LockedVMA>>,
|
||||
vma_set: HashSet<Arc<LockedVMA>>,
|
||||
/// 标志
|
||||
flags: PageFlags,
|
||||
/// 页所在的物理页帧号
|
||||
/// 页面所在物理地址
|
||||
phys_addr: PhysAddr,
|
||||
/// 在pagecache中的偏移
|
||||
index: Option<usize>,
|
||||
page_cache: Option<Arc<PageCache>>,
|
||||
/// 页面类型
|
||||
page_type: PageType,
|
||||
}
|
||||
|
||||
impl InnerPage {
|
||||
pub fn new(shared: bool, phys_addr: PhysAddr) -> Self {
|
||||
let dealloc_when_zero = !shared;
|
||||
pub fn new(phys_addr: PhysAddr, page_type: PageType, flags: PageFlags) -> Self {
|
||||
Self {
|
||||
map_count: 0,
|
||||
shared,
|
||||
free_when_zero: dealloc_when_zero,
|
||||
shm_id: None,
|
||||
anon_vma: HashSet::new(),
|
||||
flags: PageFlags::empty(),
|
||||
vma_set: HashSet::new(),
|
||||
flags,
|
||||
phys_addr,
|
||||
index: None,
|
||||
page_cache: None,
|
||||
page_type,
|
||||
}
|
||||
}
|
||||
|
||||
/// 将vma加入anon_vma
|
||||
pub fn insert_vma(&mut self, vma: Arc<LockedVMA>) {
|
||||
self.anon_vma.insert(vma);
|
||||
self.map_count += 1;
|
||||
self.vma_set.insert(vma);
|
||||
}
|
||||
|
||||
/// 将vma从anon_vma中删去
|
||||
pub fn remove_vma(&mut self, vma: &LockedVMA) {
|
||||
self.anon_vma.remove(vma);
|
||||
self.map_count -= 1;
|
||||
self.vma_set.remove(vma);
|
||||
}
|
||||
|
||||
/// 判断当前物理页是否能被回
|
||||
pub fn can_deallocate(&self) -> bool {
|
||||
self.map_count == 0 && self.free_when_zero
|
||||
self.map_count() == 0 && !self.flags.contains(PageFlags::PG_UNEVICTABLE)
|
||||
}
|
||||
|
||||
pub fn shared(&self) -> bool {
|
||||
self.shared
|
||||
}
|
||||
|
||||
pub fn shm_id(&self) -> Option<ShmId> {
|
||||
self.shm_id
|
||||
}
|
||||
|
||||
pub fn index(&self) -> Option<usize> {
|
||||
self.index
|
||||
self.map_count() > 1
|
||||
}
|
||||
|
||||
pub fn page_cache(&self) -> Option<Arc<PageCache>> {
|
||||
self.page_cache.clone()
|
||||
match &self.page_type {
|
||||
PageType::File(info) => Some(info.page_cache.clone()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_page_cache(&mut self, page_cache: Option<Arc<PageCache>>) {
|
||||
self.page_cache = page_cache;
|
||||
pub fn page_type(&self) -> &PageType {
|
||||
&self.page_type
|
||||
}
|
||||
|
||||
pub fn set_index(&mut self, index: Option<usize>) {
|
||||
self.index = index;
|
||||
}
|
||||
|
||||
pub fn set_page_cache_index(
|
||||
&mut self,
|
||||
page_cache: Option<Arc<PageCache>>,
|
||||
index: Option<usize>,
|
||||
) {
|
||||
self.page_cache = page_cache;
|
||||
self.index = index;
|
||||
}
|
||||
|
||||
pub fn set_shm_id(&mut self, shm_id: ShmId) {
|
||||
self.shm_id = Some(shm_id);
|
||||
}
|
||||
|
||||
pub fn set_dealloc_when_zero(&mut self, dealloc_when_zero: bool) {
|
||||
self.free_when_zero = dealloc_when_zero;
|
||||
pub fn set_page_type(&mut self, page_type: PageType) {
|
||||
self.page_type = page_type;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn anon_vma(&self) -> &HashSet<Arc<LockedVMA>> {
|
||||
&self.anon_vma
|
||||
pub fn vma_set(&self) -> &HashSet<Arc<LockedVMA>> {
|
||||
&self.vma_set
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn map_count(&self) -> usize {
|
||||
self.map_count
|
||||
self.vma_set.len()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@ -454,9 +598,83 @@ impl InnerPage {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn phys_address(&self) -> PhysAddr {
|
||||
fn phys_address(&self) -> PhysAddr {
|
||||
self.phys_addr
|
||||
}
|
||||
|
||||
pub unsafe fn as_slice(&self) -> &[u8] {
|
||||
core::slice::from_raw_parts(
|
||||
MMArch::phys_2_virt(self.phys_addr).unwrap().data() as *const u8,
|
||||
MMArch::PAGE_SIZE,
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe fn as_slice_mut(&mut self) -> &mut [u8] {
|
||||
core::slice::from_raw_parts_mut(
|
||||
MMArch::phys_2_virt(self.phys_addr).unwrap().data() as *mut u8,
|
||||
MMArch::PAGE_SIZE,
|
||||
)
|
||||
}
|
||||
|
||||
pub unsafe fn copy_from_slice(&mut self, slice: &[u8]) {
|
||||
assert_eq!(
|
||||
slice.len(),
|
||||
MMArch::PAGE_SIZE,
|
||||
"length of slice not match PAGE_SIZE"
|
||||
);
|
||||
core::slice::from_raw_parts_mut(
|
||||
MMArch::phys_2_virt(self.phys_addr).unwrap().data() as *mut u8,
|
||||
MMArch::PAGE_SIZE,
|
||||
)
|
||||
.copy_from_slice(slice);
|
||||
}
|
||||
|
||||
pub unsafe fn truncate(&mut self, len: usize) {
|
||||
if len > MMArch::PAGE_SIZE {
|
||||
return;
|
||||
}
|
||||
|
||||
let vaddr = unsafe { MMArch::phys_2_virt(self.phys_addr).unwrap() };
|
||||
|
||||
unsafe {
|
||||
core::slice::from_raw_parts_mut(
|
||||
(vaddr.data() + len) as *mut u8,
|
||||
MMArch::PAGE_SIZE - len,
|
||||
)
|
||||
.fill(0)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for InnerPage {
|
||||
fn drop(&mut self) {
|
||||
assert!(
|
||||
self.map_count() == 0,
|
||||
"page drop when map count is non-zero"
|
||||
);
|
||||
|
||||
unsafe {
|
||||
deallocate_page_frames(PhysPageFrame::new(self.phys_addr), PageFrameCount::new(1))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// 页面类型,包含额外的页面信息
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PageType {
|
||||
/// 普通页面,不含额外信息
|
||||
Normal,
|
||||
/// 文件映射页,含文件映射相关信息
|
||||
File(FileMapInfo),
|
||||
/// 共享内存页,记录ShmId
|
||||
Shm(ShmId),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FileMapInfo {
|
||||
pub page_cache: Arc<PageCache>,
|
||||
/// 在pagecache中的偏移
|
||||
pub index: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -634,23 +852,7 @@ impl<Arch: MemoryManagementArch> PageTable<Arch> {
|
||||
let phys = allocator.allocate_one()?;
|
||||
let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
let old_phys = entry.address().unwrap();
|
||||
let old_page = page_manager_guard.get_unwrap(&old_phys);
|
||||
let new_page =
|
||||
Arc::new(Page::new(old_page.read_irqsave().shared(), phys));
|
||||
if let Some(ref page_cache) = old_page.read_irqsave().page_cache() {
|
||||
new_page.write_irqsave().set_page_cache_index(
|
||||
Some(page_cache.clone()),
|
||||
old_page.read_irqsave().index(),
|
||||
);
|
||||
}
|
||||
|
||||
page_manager_guard.insert(phys, &new_page);
|
||||
let old_phys = entry.address().unwrap();
|
||||
let frame = MMArch::phys_2_virt(phys).unwrap().data() as *mut u8;
|
||||
frame.copy_from_nonoverlapping(
|
||||
MMArch::phys_2_virt(old_phys).unwrap().data() as *mut u8,
|
||||
MMArch::PAGE_SIZE,
|
||||
);
|
||||
page_manager_guard.copy_page(&old_phys, allocator).ok()?;
|
||||
new_table.set_entry(i, PageEntry::new(phys, entry.flags()));
|
||||
}
|
||||
}
|
||||
@ -1180,21 +1382,17 @@ impl<Arch: MemoryManagementArch, F: FrameAllocator> PageMapper<Arch, F> {
|
||||
virt: VirtAddr,
|
||||
flags: EntryFlags<Arch>,
|
||||
) -> Option<PageFlush<Arch>> {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
let phys: PhysAddr = self.frame_allocator.allocate_one()?;
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
unsafe {
|
||||
let vaddr = MMArch::phys_2_virt(phys).unwrap();
|
||||
MMArch::write_bytes(vaddr, 0, MMArch::PAGE_SIZE);
|
||||
}
|
||||
|
||||
let mut page_manager_guard: SpinLockGuard<'static, PageManager> =
|
||||
page_manager_lock_irqsave();
|
||||
if !page_manager_guard.contains(&phys) {
|
||||
page_manager_guard.insert(phys, &Arc::new(Page::new(false, phys)))
|
||||
}
|
||||
let page = page_manager_guard
|
||||
.create_one_page(
|
||||
PageType::Normal,
|
||||
PageFlags::empty(),
|
||||
&mut self.frame_allocator,
|
||||
)
|
||||
.ok()?;
|
||||
drop(page_manager_guard);
|
||||
let phys = page.phys_address();
|
||||
return self.map_phys(virt, phys, flags);
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ use crate::{
|
||||
arch::{mm::PageMapper, CurrentIrqArch, MMArch},
|
||||
exception::InterruptArch,
|
||||
filesystem::vfs::file::File,
|
||||
ipc::shm::{shm_manager_lock, ShmFlags},
|
||||
libs::{
|
||||
align::page_align_up,
|
||||
rwlock::RwLock,
|
||||
@ -35,7 +36,7 @@ use super::{
|
||||
allocator::page_frame::{
|
||||
deallocate_page_frames, PageFrameCount, PhysPageFrame, VirtPageFrame, VirtPageFrameIter,
|
||||
},
|
||||
page::{EntryFlags, Flusher, InactiveFlusher, Page, PageFlushAll},
|
||||
page::{EntryFlags, Flusher, InactiveFlusher, PageFlushAll, PageType},
|
||||
syscall::{MadvFlags, MapFlags, MremapFlags, ProtFlags},
|
||||
MemoryManagementArch, PageTableKind, VirtAddr, VirtRegion, VmFlags,
|
||||
};
|
||||
@ -841,7 +842,6 @@ impl Drop for UserMapper {
|
||||
deallocate_page_frames(
|
||||
PhysPageFrame::new(self.utable.table().phys()),
|
||||
PageFrameCount::new(1),
|
||||
&mut page_manager_lock_irqsave(),
|
||||
)
|
||||
};
|
||||
}
|
||||
@ -1152,12 +1152,35 @@ impl LockedVMA {
|
||||
|
||||
pub fn unmap(&self, mapper: &mut PageMapper, mut flusher: impl Flusher<MMArch>) {
|
||||
// todo: 如果当前vma与文件相关,完善文件相关的逻辑
|
||||
|
||||
let mut guard = self.lock_irqsave();
|
||||
|
||||
// 获取物理页的anon_vma的守卫
|
||||
let mut page_manager_guard: SpinLockGuard<'_, crate::mm::page::PageManager> =
|
||||
page_manager_lock_irqsave();
|
||||
|
||||
// 获取映射的物理地址
|
||||
if let Some((paddr, _flags)) = mapper.translate(guard.region().start()) {
|
||||
// 如果是共享页,执行释放操作
|
||||
let page = page_manager_guard.get(&paddr).unwrap();
|
||||
let page_guard = page.read_irqsave();
|
||||
if let PageType::Shm(shm_id) = page_guard.page_type() {
|
||||
let mut shm_manager_guard = shm_manager_lock();
|
||||
if let Some(kernel_shm) = shm_manager_guard.get_mut(shm_id) {
|
||||
// 更新最后一次断开连接时间
|
||||
kernel_shm.update_dtim();
|
||||
|
||||
// 映射计数减少
|
||||
kernel_shm.decrease_count();
|
||||
|
||||
// 释放shm_id
|
||||
if kernel_shm.map_count() == 0 && kernel_shm.mode().contains(ShmFlags::SHM_DEST)
|
||||
{
|
||||
shm_manager_guard.free_id(shm_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for page in guard.region.pages() {
|
||||
if mapper.translate(page.virt_address()).is_none() {
|
||||
continue;
|
||||
@ -1167,18 +1190,13 @@ impl LockedVMA {
|
||||
|
||||
// 从anon_vma中删除当前VMA
|
||||
let page = page_manager_guard.get_unwrap(&paddr);
|
||||
page.write_irqsave().remove_vma(self);
|
||||
let mut page_guard = page.write_irqsave();
|
||||
page_guard.remove_vma(self);
|
||||
|
||||
// 如果物理页的anon_vma链表长度为0并且不是共享页,则释放物理页.
|
||||
if page.read_irqsave().can_deallocate() {
|
||||
unsafe {
|
||||
drop(page);
|
||||
deallocate_page_frames(
|
||||
PhysPageFrame::new(paddr),
|
||||
PageFrameCount::new(1),
|
||||
&mut page_manager_guard,
|
||||
)
|
||||
};
|
||||
// 如果物理页的vma链表长度为0并且未标记为不可回收,则释放物理页.
|
||||
// TODO 后续由lru释放物理页面
|
||||
if page_guard.can_deallocate() {
|
||||
page_manager_guard.remove_page(&paddr);
|
||||
}
|
||||
|
||||
flusher.consume(flush);
|
||||
@ -1659,9 +1677,7 @@ impl VMA {
|
||||
return Ok(r);
|
||||
}
|
||||
|
||||
pub fn page_address(&self, page: &Arc<Page>) -> Result<VirtAddr, SystemError> {
|
||||
let page_guard = page.read_irqsave();
|
||||
let index = page_guard.index().unwrap();
|
||||
pub fn page_address(&self, index: usize) -> Result<VirtAddr, SystemError> {
|
||||
if index >= self.file_pgoff.unwrap() {
|
||||
let address =
|
||||
self.region.start + ((index - self.file_pgoff.unwrap()) << MMArch::PAGE_SHIFT);
|
||||
|
@ -1,14 +1,15 @@
|
||||
use super::{PerfEventOps, Result};
|
||||
use crate::arch::mm::LockedFrameAllocator;
|
||||
use crate::arch::MMArch;
|
||||
use crate::filesystem::vfs::file::PageCache;
|
||||
use crate::filesystem::page_cache::PageCache;
|
||||
use crate::filesystem::vfs::{FilePrivateData, FileSystem, IndexNode};
|
||||
use crate::include::bindings::linux_bpf::{
|
||||
perf_event_header, perf_event_mmap_page, perf_event_type,
|
||||
};
|
||||
use crate::libs::align::page_align_up;
|
||||
use crate::libs::spinlock::{SpinLock, SpinLockGuard};
|
||||
use crate::mm::allocator::page_frame::{FrameAllocator, PageFrameCount, PhysPageFrame};
|
||||
use crate::mm::page::{page_manager_lock_irqsave, Page};
|
||||
use crate::mm::allocator::page_frame::{PageFrameCount, PhysPageFrame};
|
||||
use crate::mm::page::{page_manager_lock_irqsave, PageFlags, PageType};
|
||||
use crate::mm::{MemoryManagementArch, PhysAddr};
|
||||
use crate::perf::util::{LostSamples, PerfProbeArgs, PerfSample, SampleHeader};
|
||||
use alloc::string::String;
|
||||
@ -240,18 +241,17 @@ impl BpfPerfEvent {
|
||||
}
|
||||
pub fn do_mmap(&self, _start: usize, len: usize, offset: usize) -> Result<()> {
|
||||
let mut data = self.data.lock();
|
||||
// alloc page frame
|
||||
let (phy_addr, page_count) =
|
||||
unsafe { LockedFrameAllocator.allocate(PageFrameCount::new(len / PAGE_SIZE)) }
|
||||
.ok_or(SystemError::ENOSPC)?;
|
||||
let mut page_manager_guard = page_manager_lock_irqsave();
|
||||
let mut cur_phys = PhysPageFrame::new(phy_addr);
|
||||
for i in 0..page_count.data() {
|
||||
let page = Arc::new(Page::new(true, cur_phys.phys_address()));
|
||||
let paddr = cur_phys.phys_address();
|
||||
page_manager_guard.insert(paddr, &page);
|
||||
data.page_cache.add_page(i, &page);
|
||||
cur_phys = cur_phys.next();
|
||||
let (phy_addr, pages) = page_manager_guard.create_pages(
|
||||
PageType::Normal,
|
||||
PageFlags::PG_UNEVICTABLE,
|
||||
&mut LockedFrameAllocator,
|
||||
PageFrameCount::new(page_align_up(len) / PAGE_SIZE),
|
||||
)?;
|
||||
for i in 0..pages.len() {
|
||||
data.page_cache
|
||||
.lock_irqsave()
|
||||
.add_page(i, pages.get(i).unwrap());
|
||||
}
|
||||
let virt_addr = unsafe { MMArch::phys_2_virt(phy_addr) }.ok_or(SystemError::EFAULT)?;
|
||||
// create mmap page
|
||||
|
@ -5,7 +5,8 @@ use crate::bpf::helper::BPF_HELPER_FUN_SET;
|
||||
use crate::bpf::prog::BpfProg;
|
||||
use crate::debug::kprobe::args::KprobeInfo;
|
||||
use crate::debug::kprobe::{register_kprobe, unregister_kprobe, LockKprobe};
|
||||
use crate::filesystem::vfs::file::{File, PageCache};
|
||||
use crate::filesystem::page_cache::PageCache;
|
||||
use crate::filesystem::vfs::file::File;
|
||||
use crate::filesystem::vfs::{FilePrivateData, FileSystem, IndexNode};
|
||||
use crate::libs::casting::DowncastArc;
|
||||
use crate::libs::spinlock::SpinLockGuard;
|
||||
|
@ -2,7 +2,8 @@ mod bpf;
|
||||
mod kprobe;
|
||||
mod util;
|
||||
|
||||
use crate::filesystem::vfs::file::{File, FileMode, PageCache};
|
||||
use crate::filesystem::page_cache::PageCache;
|
||||
use crate::filesystem::vfs::file::{File, FileMode};
|
||||
use crate::filesystem::vfs::syscall::ModeType;
|
||||
use crate::filesystem::vfs::{
|
||||
FilePrivateData, FileSystem, FileType, FsInfo, IndexNode, Metadata, SuperBlock,
|
||||
|
Loading…
x
Reference in New Issue
Block a user