diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 414df828b..dd25e04ac 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -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" } diff --git a/kernel/src/driver/net/dma.rs b/kernel/src/driver/net/dma.rs index e03fe86a5..fcfe1c948 100644 --- a/kernel/src/driver/net/dma.rs +++ b/kernel/src/driver/net/dma.rs @@ -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, 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; } diff --git a/kernel/src/driver/virtio/virtio_impl.rs b/kernel/src/driver/virtio/virtio_impl.rs index 0608a0ce4..878147487 100644 --- a/kernel/src/driver/virtio/virtio_impl.rs +++ b/kernel/src/driver/virtio/virtio_impl.rs @@ -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; } diff --git a/kernel/src/filesystem/fat/fs.rs b/kernel/src/filesystem/fat/fs.rs index fdd43859b..88712c458 100644 --- a/kernel/src/filesystem/fat/fs.rs +++ b/kernel/src/filesystem/fat/fs.rs @@ -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) { + 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, 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, - ) -> Result { - let mut guard: SpinLockGuard = self.0.lock(); + fn read_sync(&self, offset: usize, buf: &mut [u8]) -> Result { + let guard: SpinLockGuard = 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,25 +1416,20 @@ impl IndexNode for LockedFATInode { } } - fn write_at( - &self, - offset: usize, - len: usize, - buf: &[u8], - _data: SpinLockGuard, - ) -> Result { + fn write_sync(&self, offset: usize, buf: &[u8]) -> Result { let mut guard: SpinLockGuard = self.0.lock(); let fs: &Arc = &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(); + 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); @@ -1440,6 +1437,74 @@ impl IndexNode for LockedFATInode { } } + fn read_at( + &self, + offset: usize, + len: usize, + buf: &mut [u8], + data: SpinLockGuard, + ) -> Result { + 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, + ) -> Result { + 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, + ) -> Result { + 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, + ) -> Result { + 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( &self, name: &str, @@ -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 = self.0.lock(); let fs: &Arc = &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), diff --git a/kernel/src/filesystem/mod.rs b/kernel/src/filesystem/mod.rs index 772d21f41..59bda2a15 100644 --- a/kernel/src/filesystem/mod.rs +++ b/kernel/src/filesystem/mod.rs @@ -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; diff --git a/kernel/src/filesystem/page_cache.rs b/kernel/src/filesystem/page_cache.rs new file mode 100644 index 000000000..7f5959331 --- /dev/null +++ b/kernel/src/filesystem/page_cache.rs @@ -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, + inode: Lazy>, +} + +#[derive(Debug)] +pub struct InnerPageCache { + pages: HashMap>, + page_cache_ref: Weak, +} + +impl InnerPageCache { + pub fn new(page_cache_ref: Weak) -> InnerPageCache { + Self { + pages: HashMap::new(), + page_cache_ref, + } + } + + pub fn add_page(&mut self, offset: usize, page: &Arc) { + self.pages.insert(offset, page.clone()); + } + + pub fn get_page(&self, offset: usize) -> Option> { + self.pages.get(&offset).cloned() + } + + pub fn remove_page(&mut self, offset: usize) -> Option> { + 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 { + 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 { + 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>) -> Arc { + Arc::new_cyclic(|weak| Self { + inner: SpinLock::new(InnerPageCache::new(weak.clone())), + inode: { + let v: Lazy> = Lazy::new(); + if let Some(inode) = inode { + v.init(inode); + } + v + }, + }) + } + + pub fn inode(&self) -> Option> { + self.inode.try_get().cloned() + } + + pub fn set_inode(&self, inode: Weak) -> Result<(), SystemError> { + if self.inode.initialized() { + return Err(SystemError::EINVAL); + } + self.inode.init(inode); + Ok(()) + } + + pub fn lock_irqsave(&self) -> SpinLockGuard { + self.inner.lock_irqsave() + } +} diff --git a/kernel/src/filesystem/vfs/file.rs b/kernel/src/filesystem/vfs/file.rs index 3762474ea..e92990ac7 100644 --- a/kernel/src/filesystem/vfs/file.rs +++ b/kernel/src/filesystem/vfs/file.rs @@ -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>>, - inode: Lazy>, -} - -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::>>(), - ) - .finish() - } -} - -impl PageCache { - pub fn new(inode: Option>) -> Arc { - let page_cache = Self { - xarray: SpinLock::new(XArray::new()), - inode: { - let v: Lazy> = Lazy::new(); - if let Some(inode) = inode { - v.init(inode); - } - v - }, - }; - Arc::new(page_cache) - } - - pub fn inode(&self) -> Option> { - self.inode.try_get().cloned() - } - - pub fn add_page(&self, offset: usize, page: &Arc) { - 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> { - 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) -> 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 { 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 { self.do_write( self.offset.load(core::sync::atomic::Ordering::SeqCst), @@ -309,16 +242,21 @@ impl File { return Err(SystemError::ENOBUFS); } - let len = self - .inode - .read_at(offset, len, buf, self.private_data.lock()) - .map_err(|e| { - if e == SystemError::ERESTARTSYS { - SystemError::EINTR - } else { - e - } - })?; + let r = 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()) + }; + + let len = r.map_err(|e| { + if e == SystemError::ERESTARTSYS { + SystemError::EINTR + } else { + e + } + })?; if update_offset { self.offset diff --git a/kernel/src/filesystem/vfs/mod.rs b/kernel/src/filesystem/vfs/mod.rs index 67b7643a3..50f616192 100644 --- a/kernel/src/filesystem/vfs/mod.rs +++ b/kernel/src/filesystem/vfs/mod.rs @@ -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 { + return Err(SystemError::ENOSYS); + } + + fn write_sync(&self, _offset: usize, _buf: &[u8]) -> Result { + return Err(SystemError::ENOSYS); + } + /// @brief 打开文件 /// /// @return 成功:Ok() @@ -184,6 +190,52 @@ pub trait IndexNode: Any + Sync + Send + Debug + CastFromSync { _data: SpinLockGuard, ) -> Result; + /// # 在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, + ) -> Result { + 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, + ) -> Result { + return Err(SystemError::ENOSYS); + } + /// @brief 获取当前inode的状态。 /// /// @return PollStatus结构体 diff --git a/kernel/src/filesystem/vfs/mount.rs b/kernel/src/filesystem/vfs/mount.rs index 12f122b8c..35d221d8f 100644 --- a/kernel/src/filesystem/vfs/mount.rs +++ b/kernel/src/filesystem/vfs/mount.rs @@ -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, + ) -> Result { + self.inner_inode.read_direct(offset, len, buf, data) + } + + fn write_direct( + &self, + offset: usize, + len: usize, + buf: &[u8], + data: SpinLockGuard, + ) -> Result { + self.inner_inode.write_direct(offset, len, buf, data) + } + #[inline] fn fs(&self) -> Arc { return self.mount_fs.clone(); diff --git a/kernel/src/ipc/shm.rs b/kernel/src/ipc/shm.rs index 56ecdc67c..e2c0187fe 100644 --- a/kernel/src/ipc/shm.rs +++ b/kernel/src/ipc/shm.rs @@ -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 = 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::>(), - ); - - 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; + } } /// 共享内存权限信息 diff --git a/kernel/src/ipc/syscall.rs b/kernel/src/ipc/syscall.rs index 2d0b9b6b2..1b5b93cb7 100644 --- a/kernel/src/ipc/syscall.rs +++ b/kernel/src/ipc/syscall.rs @@ -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}, @@ -404,6 +403,9 @@ impl Syscall { // 更新最后一次连接时间 kernel_shm.update_atim(); + // 映射计数增加 + kernel_shm.increase_count(); + Ok(r) } @@ -432,29 +434,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 = PageFlushAll::new(); vma.unmap(&mut address_write_guard.user_mapper.utable, flusher); diff --git a/kernel/src/mm/allocator/page_frame.rs b/kernel/src/mm/allocator/page_frame.rs index 180a2ac25..a7e9c8ba4 100644 --- a/kernel/src/mm/allocator/page_frame.rs +++ b/kernel/src/mm/allocator/page_frame.rs @@ -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(); - } + }; } diff --git a/kernel/src/mm/fault.rs b/kernel/src/mm/fault.rs index e0aa1622a..0fa8e6b0e 100644 --- a/kernel/src/mm/fault.rs +++ b/kernel/src/mm/fault.rs @@ -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, /// 缺页对应PageCache中的文件页 page: Option>, @@ -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()); diff --git a/kernel/src/mm/page.rs b/kernel/src/mm/page.rs index f3d900697..d635a4f32 100644 --- a/kernel/src/mm/page.rs +++ b/kernel/src/mm/page.rs @@ -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) { - self.phys2page.insert(paddr, page.clone()); + fn insert(&mut self, page: &Arc) -> Result, 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)`: 新页面 + /// - `Err(SystemError)`: 错误码 + pub fn create_one_page( + &mut self, + page_type: PageType, + flags: PageFlags, + allocator: &mut dyn FrameAllocator, + ) -> Result, 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>))`: 页面起始物理地址,新页面集合 + /// - `Err(SystemError)`: 错误码 + pub fn create_pages( + &mut self, + page_type: PageType, + flags: PageFlags, + allocator: &mut dyn FrameAllocator, + count: PageFrameCount, + ) -> Result<(PhysAddr, Vec>), 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> = 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)`: 新页面 + /// - `Err(SystemError)`: 错误码 + pub fn copy_page( + &mut self, + old_phys: &PhysAddr, + allocator: &mut dyn FrameAllocator, + ) -> Result, 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> = None; @@ -180,28 +291,31 @@ impl PageReclaimer { self.lru.put(paddr, page.clone()); } + pub fn remove_page(&mut self, paddr: &PhysAddr) -> Option> { + 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, unmap: bool) { - if !unmap { - page.write_irqsave().remove_flags(PageFlags::PG_DIRTY); - } + pub fn page_writeback(guard: &mut RwLockWriteGuard, unmap: bool) { + // log::debug!("page writeback: {:?}", guard.phys_addr); + + 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 page.read_irqsave().anon_vma() { + 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, + /// 页面所在物理地址 + 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`: 新页面 + fn new(phys_addr: PhysAddr, page_type: PageType, flags: PageFlags) -> Arc { + 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)`: 新页面 + /// - `Err(SystemError)`: 错误码 + fn copy( + old_guard: RwLockReadGuard, + new_phys: PhysAddr, + ) -> Result, 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 { @@ -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, /// 映射到当前page的VMA - anon_vma: HashSet>, + vma_set: HashSet>, /// 标志 flags: PageFlags, - /// 页所在的物理页帧号 + /// 页面所在物理地址 phys_addr: PhysAddr, - /// 在pagecache中的偏移 - index: Option, - page_cache: Option>, + /// 页面类型 + 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) { - 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 { - self.shm_id - } - - pub fn index(&self) -> Option { - self.index + self.map_count() > 1 } pub fn page_cache(&self) -> Option> { - self.page_cache.clone() - } - - pub fn set_page_cache(&mut self, page_cache: Option>) { - self.page_cache = page_cache; - } - - pub fn set_index(&mut self, index: Option) { - self.index = index; - } - - pub fn set_page_cache_index( - &mut self, - page_cache: Option>, - index: Option, - ) { - self.page_cache = page_cache; - self.index = index; + match &self.page_type { + PageType::File(info) => Some(info.page_cache.clone()), + _ => None, + } } - pub fn set_shm_id(&mut self, shm_id: ShmId) { - self.shm_id = Some(shm_id); + pub fn page_type(&self) -> &PageType { + &self.page_type } - 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> { - &self.anon_vma + pub fn vma_set(&self) -> &HashSet> { + &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中的偏移 + pub index: usize, } #[derive(Debug)] @@ -634,23 +852,7 @@ impl PageTable { 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 PageMapper { virt: VirtAddr, flags: EntryFlags, ) -> Option> { - 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); } diff --git a/kernel/src/mm/ucontext.rs b/kernel/src/mm/ucontext.rs index 81abd4b0c..04d953b28 100644 --- a/kernel/src/mm/ucontext.rs +++ b/kernel/src/mm/ucontext.rs @@ -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) { // 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); - - // 如果物理页的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, - ) - }; + let mut page_guard = page.write_irqsave(); + page_guard.remove_vma(self); + + // 如果物理页的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) -> Result { - let page_guard = page.read_irqsave(); - let index = page_guard.index().unwrap(); + pub fn page_address(&self, index: usize) -> Result { if index >= self.file_pgoff.unwrap() { let address = self.region.start + ((index - self.file_pgoff.unwrap()) << MMArch::PAGE_SHIFT); diff --git a/kernel/src/perf/bpf.rs b/kernel/src/perf/bpf.rs index b283b2e54..a915ad56c 100644 --- a/kernel/src/perf/bpf.rs +++ b/kernel/src/perf/bpf.rs @@ -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; @@ -232,18 +233,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 diff --git a/kernel/src/perf/kprobe.rs b/kernel/src/perf/kprobe.rs index 54ac829bc..7b9fdfb92 100644 --- a/kernel/src/perf/kprobe.rs +++ b/kernel/src/perf/kprobe.rs @@ -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; diff --git a/kernel/src/perf/mod.rs b/kernel/src/perf/mod.rs index 0b6de2adb..99d2e25ad 100644 --- a/kernel/src/perf/mod.rs +++ b/kernel/src/perf/mod.rs @@ -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,