From 22053aad99b8e2fab01215bea32bcd706b558fd6 Mon Sep 17 00:00:00 2001 From: Chen Chengjun Date: Wed, 11 Feb 2026 09:25:01 +0000 Subject: [PATCH] Modify some related usages of PageCache and VMO --- kernel/src/fs/exfat/fs.rs | 14 +++--- kernel/src/fs/exfat/inode.rs | 67 +++++++++++++---------------- kernel/src/fs/ext2/block_group.rs | 17 +++----- kernel/src/fs/ext2/dir.rs | 23 +++++----- kernel/src/fs/ext2/inode.rs | 50 +++++++++++----------- kernel/src/fs/ext2/prelude.rs | 2 +- kernel/src/fs/ramfs/fs.rs | 65 +++++++++++----------------- kernel/src/fs/ramfs/memfd.rs | 13 +----- kernel/src/fs/utils/mod.rs | 6 ++- kernel/src/vdso.rs | 2 +- kernel/src/vm/vmar/vm_mapping.rs | 71 ++++++++++++++++++------------- kernel/src/vm/vmo/options.rs | 43 ++++++++++++------- kernel/src/vm/vmo/pager.rs | 58 ------------------------- 13 files changed, 183 insertions(+), 248 deletions(-) delete mode 100644 kernel/src/vm/vmo/pager.rs diff --git a/kernel/src/fs/exfat/fs.rs b/kernel/src/fs/exfat/fs.rs index 54ecbaa81..7215f3980 100644 --- a/kernel/src/fs/exfat/fs.rs +++ b/kernel/src/fs/exfat/fs.rs @@ -27,8 +27,8 @@ use crate::{ exfat::{constants::*, inode::Ino}, registry::{FsProperties, FsType}, utils::{ - CachePage, FileSystem, FsEventSubscriberStats, FsFlags, Inode, PageCache, - PageCacheBackend, SuperBlock, + FileSystem, FsEventSubscriberStats, FsFlags, Inode, LockedCachePage, PageCache, + PageCacheBackend, PageCacheOps, SuperBlock, }, }, prelude::*, @@ -83,7 +83,7 @@ impl ExfatFs { fat_cache: RwLock::new(LruCache::::new( NonZeroUsize::new(FAT_LRU_CACHE_SIZE).unwrap(), )), - meta_cache: PageCache::with_capacity(fs_size, weak_self.clone() as _).unwrap(), + meta_cache: PageCacheOps::with_capacity(fs_size, weak_self.clone() as _).unwrap(), mutex: Mutex::new(()), fs_event_subscriber_stats: FsEventSubscriberStats::new(), }); @@ -153,17 +153,17 @@ impl ExfatFs { } pub(super) fn sync_meta_at(&self, range: core::ops::Range) -> Result<()> { - self.meta_cache.pages().decommit(range)?; + self.meta_cache.flush_range(range)?; Ok(()) } pub(super) fn write_meta_at(&self, offset: usize, buf: &[u8]) -> Result<()> { - self.meta_cache.pages().write_bytes(offset, buf)?; + self.meta_cache.write_bytes(offset, buf)?; Ok(()) } pub(super) fn read_meta_at(&self, offset: usize, buf: &mut [u8]) -> Result<()> { - self.meta_cache.pages().read_bytes(offset, buf)?; + self.meta_cache.read_bytes(offset, buf)?; Ok(()) } @@ -422,7 +422,7 @@ impl FileSystem for ExfatFs { for inode in self.inodes.read().values() { inode.sync_all()?; } - self.meta_cache.evict_range(0..self.fs_size())?; + self.meta_cache.flush_range(0..self.fs_size())?; Ok(()) } diff --git a/kernel/src/fs/exfat/inode.rs b/kernel/src/fs/exfat/inode.rs index 33f9ca703..860eff466 100644 --- a/kernel/src/fs/exfat/inode.rs +++ b/kernel/src/fs/exfat/inode.rs @@ -29,8 +29,9 @@ use crate::{ exfat::{dentry::ExfatDentryIterator, fat::ExfatChain, fs::ExfatFs}, path::{is_dot, is_dot_or_dotdot, is_dotdot}, utils::{ - CachePage, DirentVisitor, Extension, Inode, InodeIo, InodeMode, InodeType, Metadata, - MknodType, PageCache, PageCacheBackend, StatusFlags, SymbolicLink, mkmod, + DirentVisitor, Extension, Inode, InodeIo, InodeMode, InodeType, LockedCachePage, + Metadata, MknodType, PageCache, PageCacheBackend, PageCacheOps, StatusFlags, + SymbolicLink, mkmod, }, }, prelude::*, @@ -254,7 +255,7 @@ impl ExfatInodeInner { return Ok((0, 0)); } - let iterator = ExfatDentryIterator::new(self.page_cache.pages(), 0, Some(self.size))?; + let iterator = ExfatDentryIterator::new(&self.page_cache, 0, Some(self.size))?; let mut sub_inodes = 0; let mut sub_dirs = 0; for dentry_result in iterator { @@ -357,7 +358,7 @@ impl ExfatInodeInner { page_cache.write_bytes(start_off, &bytes)?; if sync { - page_cache.decommit(start_off..start_off + bytes.len())?; + page_cache.flush_range(start_off..start_off + bytes.len())?; } Ok(()) @@ -383,7 +384,7 @@ impl ExfatInodeInner { let fs = self.fs(); let cluster_size = fs.cluster_size(); - let mut iter = ExfatDentryIterator::new(self.page_cache.pages(), offset, None)?; + let mut iter = ExfatDentryIterator::new(&self.page_cache, offset, None)?; let mut dir_read = 0; let mut current_off = offset; @@ -590,7 +591,7 @@ impl ExfatInodeInner { } fn sync_data(&self, fs_guard: &MutexGuard<()>) -> Result<()> { - self.page_cache.evict_range(0..self.size)?; + self.page_cache.flush_range(0..self.size)?; Ok(()) } @@ -634,7 +635,7 @@ impl ExfatInode { let end = file_size.min(offset + writer.avail()); (start, end - start) }; - inner.page_cache.pages().read(read_off, writer)?; + inner.page_cache.read(read_off, writer)?; inner.upgrade().update_atime()?; Ok(read_len) @@ -663,7 +664,7 @@ impl ExfatInode { inner .page_cache - .discard_range(read_off..read_off + read_len); + .discard_range(read_off..read_off + read_len)?; let bio_segment = BioSegment::alloc(1, BioDirection::FromDevice); @@ -709,14 +710,14 @@ impl ExfatInode { if new_size > file_allocated_size { inner.resize(new_size, &fs_guard)?; } - inner.page_cache.resize(new_size)?; + inner.page_cache.resize(new_size, file_size)?; } new_size.max(file_size) }; // Locks released here, so that file write can be parallelized. let inner = self.inner.upread(); - inner.page_cache.pages().write(offset, reader)?; + inner.page_cache.write(offset, reader)?; // Update timestamps and size. { @@ -754,7 +755,7 @@ impl ExfatInode { let start = offset.min(file_size); let end = end_offset.min(file_size); - inner.page_cache.discard_range(start..end); + inner.page_cache.discard_range(start..end)?; let new_size = { let mut inner = inner.upgrade(); @@ -764,7 +765,7 @@ impl ExfatInode { if end_offset > file_allocated_size { inner.resize(end_offset, &fs_guard)?; } - inner.page_cache.resize(end_offset)?; + inner.page_cache.resize(end_offset, file_size)?; } file_size.max(end_offset) }; @@ -813,8 +814,9 @@ impl ExfatInode { let inner = self.inner.write(); let fs = inner.fs(); let fs_guard = fs.lock(); - self.inner.write().resize(0, &fs_guard)?; - self.inner.read().page_cache.resize(0)?; + let mut inner = self.inner.write(); + inner.resize(0, &fs_guard)?; + inner.page_cache.resize(0, inner.size)?; Ok(()) } @@ -845,7 +847,6 @@ impl ExfatInode { let size = root_chain.num_clusters() as usize * sb.cluster_size as usize; let name = ExfatName::new(); - let inode = Arc::new_cyclic(|weak_self| ExfatInode { inner: RwMutex::new(ExfatInodeInner { ino: EXFAT_ROOT_INO, @@ -866,7 +867,7 @@ impl ExfatInode { is_deleted: false, parent_hash: 0, fs: fs_weak, - page_cache: PageCache::with_capacity(size, weak_self.clone() as _).unwrap(), + page_cache: PageCacheOps::with_capacity(size, weak_self.clone() as _).unwrap(), }), extension: Extension::new(), }); @@ -976,7 +977,7 @@ impl ExfatInode { is_deleted: false, parent_hash, fs: fs_weak, - page_cache: PageCache::with_capacity(size, weak_self.clone() as _).unwrap(), + page_cache: PageCacheOps::with_capacity(size, weak_self.clone() as _).unwrap(), }), extension: Extension::new(), }); @@ -1019,8 +1020,7 @@ impl ExfatInode { fn find_empty_dentries(&self, num_dentries: usize, fs_guard: &MutexGuard<()>) -> Result { let inner = self.inner.upread(); - let dentry_iterator = - ExfatDentryIterator::new(inner.page_cache.pages(), 0, Some(inner.size))?; + let dentry_iterator = ExfatDentryIterator::new(&inner.page_cache, 0, Some(inner.size))?; let mut contiguous_unused = 0; let mut entry_id = 0; @@ -1063,15 +1063,16 @@ impl ExfatInode { inner.size_allocated = new_size_allocated; inner.size = new_size_allocated; - inner.page_cache.resize(new_size_allocated)?; + inner + .page_cache + .resize(new_size_allocated, old_size_allocated)?; } let inner = self.inner.read(); // We need to write unused dentries (i.e. 0) to page cache. inner .page_cache - .pages() - .clear(old_size_allocated..new_size_allocated)?; + .fill_zeros(old_size_allocated..new_size_allocated)?; Ok(entry_id) } @@ -1106,7 +1107,6 @@ impl ExfatInode { let inner = self.inner.upread(); inner .page_cache - .pages() .write_bytes(start_off, &dentry_set.to_le_bytes())?; let mut inner = inner.upgrade(); @@ -1144,11 +1144,7 @@ impl ExfatInode { let fs = self.inner.read().fs(); let mut buf = vec![0; len]; - self.inner - .read() - .page_cache - .pages() - .read_bytes(offset, &mut buf)?; + self.inner.read().page_cache.read_bytes(offset, &mut buf)?; let num_dentry = len / DENTRY_SIZE; @@ -1166,11 +1162,7 @@ impl ExfatInode { buf[buf_offset] &= 0x7F; } - self.inner - .read() - .page_cache - .pages() - .write_bytes(offset, &buf)?; + self.inner.read().page_cache.write_bytes(offset, &buf)?; // FIXME: We must make sure that there are no spare tailing clusters in a directory. Ok(()) @@ -1242,8 +1234,9 @@ impl ExfatInode { let is_dir = inode.inner.read().inode_type.is_directory(); if delete_contents { if is_dir { - inode.inner.write().resize(0, fs_guard)?; - inode.inner.read().page_cache.resize(0)?; + let mut inner = inode.inner.write(); + inner.resize(0, fs_guard)?; + inner.page_cache.resize(0, inner.size)?; } // Set the delete flag. inode.inner.write().is_deleted = true; @@ -1344,7 +1337,7 @@ impl Inode for ExfatInode { // We will delay updating the page_cache size when enlarging an inode until the real write. if new_size < file_size { - self.inner.read().page_cache.resize(new_size)?; + self.inner.read().page_cache.resize(new_size, file_size)?; } // Sync this inode since size has changed. @@ -1449,7 +1442,7 @@ impl Inode for ExfatInode { } fn page_cache(&self) -> Option> { - Some(self.inner.read().page_cache.pages().clone()) + Some(self.inner.read().page_cache.clone()) } fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result> { diff --git a/kernel/src/fs/ext2/block_group.rs b/kernel/src/fs/ext2/block_group.rs index a9e3f1e96..8cebb042f 100644 --- a/kernel/src/fs/ext2/block_group.rs +++ b/kernel/src/fs/ext2/block_group.rs @@ -9,7 +9,7 @@ use super::{ prelude::*, super_block::SuperBlock, }; -use crate::fs::utils::IdBitmap; +use crate::fs::utils::{IdBitmap, LockedCachePage}; /// Blocks are clustered into block groups in order to reduce fragmentation and minimise /// the amount of head seeking when reading a large amount of consecutive data. @@ -91,7 +91,7 @@ impl BlockGroup { }; let raw_inodes_cache = - PageCache::with_capacity(raw_inodes_size, Arc::downgrade(&bg_impl) as _)?; + PageCacheOps::with_capacity(raw_inodes_size, Arc::downgrade(&bg_impl) as _)?; Ok(Self { idx, @@ -134,10 +134,7 @@ impl BlockGroup { let fs = self.fs(); let raw_inode = { let offset = (inode_idx as usize) * fs.inode_size(); - self.raw_inodes_cache - .pages() - .read_val::(offset) - .unwrap() + self.raw_inodes_cache.read_val::(offset).unwrap() }; let inode_desc = Dirty::new(InodeDesc::try_from(raw_inode)?); let ino = inode_idx + self.idx as u32 * fs.inodes_per_group() + 1; @@ -217,10 +214,7 @@ impl BlockGroup { /// Writes back the raw inode metadata to the raw inode metadata cache. pub fn sync_raw_inode(&self, inode_idx: u32, raw_inode: &RawInode) { let offset = (inode_idx as usize) * self.fs().inode_size(); - self.raw_inodes_cache - .pages() - .write_val(offset, raw_inode) - .unwrap(); + self.raw_inodes_cache.write_val(offset, raw_inode).unwrap(); } /// Writes back the metadata of this group. @@ -296,8 +290,7 @@ impl BlockGroup { // Writes back the raw inode metadata. self.raw_inodes_cache - .pages() - .decommit(0..self.bg_impl.raw_inodes_size)?; + .flush_range(0..self.bg_impl.raw_inodes_size)?; Ok(()) } diff --git a/kernel/src/fs/ext2/dir.rs b/kernel/src/fs/ext2/dir.rs index ec43d7505..3551bc8be 100644 --- a/kernel/src/fs/ext2/dir.rs +++ b/kernel/src/fs/ext2/dir.rs @@ -257,7 +257,7 @@ impl<'a> DirEntryReader<'a> { let name_buf = &mut self.name_buf.as_mut().unwrap()[..name_len]; let offset = entry_item.offset + DirEntry::HEADER_LEN; - self.page_cache.pages().read_bytes(offset, name_buf)?; + self.page_cache.read_bytes(offset, name_buf)?; Ok(name_buf) } } @@ -265,13 +265,12 @@ impl<'a> DirEntryReader<'a> { impl DirEntryIter<'_> { /// Reads a `DirEntryItem` at the current offset. fn read_next_dir_entry(&mut self) -> Option { - if self.offset >= self.page_cache.pages().size() { + if self.offset >= self.page_cache.size() { return None; }; let header = self .page_cache - .pages() .read_val::(self.offset) .ok()?; @@ -391,9 +390,8 @@ impl<'a> DirEntryWriter<'a> { /// Writes a `DirEntry` at the current offset. The name is written after the header. pub fn write_entry(&mut self, header: &DirEntryHeader, name: &str) -> Result<()> { - self.page_cache.pages().write_val(self.offset, header)?; + self.page_cache.write_val(self.offset, header)?; self.page_cache - .pages() .write_bytes(self.offset + DirEntry::HEADER_LEN, name.as_bytes())?; self.offset += header.record_len as usize; @@ -402,16 +400,17 @@ impl<'a> DirEntryWriter<'a> { /// Writes the header of a `DirEntry` at the current offset. pub fn write_header_only(&mut self, header: &DirEntryHeader) -> Result<()> { - self.page_cache.pages().write_val(self.offset, header)?; + self.page_cache.write_val(self.offset, header)?; self.offset += header.record_len as usize; Ok(()) } /// Initializes two special `DirEntry`s ("." and "..") with the given inode numbers. pub fn init_dir(&mut self, self_ino: u32, parent_ino: u32) -> Result<()> { - debug_assert!(self.page_cache.pages().size() == 0 && self.offset == 0); + let old_size = self.page_cache.size(); + debug_assert!(old_size == 0 && self.offset == 0); - self.page_cache.pages().resize(BLOCK_SIZE)?; + self.page_cache.resize(BLOCK_SIZE, old_size)?; let self_header = DirEntryHeader::new(self_ino, InodeType::Dir, 1); self.write_entry(&self_header, ".")?; @@ -480,9 +479,9 @@ impl<'a> DirEntryWriter<'a> { fn append_entry_in_the_end(&mut self, mut header: DirEntryHeader, name: &str) -> Result<()> { // Resize and append it at the new block. - let old_size = self.page_cache.pages().size(); + let old_size = self.page_cache.size(); let new_size = old_size + BLOCK_SIZE; - self.page_cache.resize(new_size)?; + self.page_cache.resize(new_size, old_size)?; header.record_len = BLOCK_SIZE as _; self.offset = old_size; @@ -513,7 +512,7 @@ impl<'a> DirEntryWriter<'a> { if is_last_entry { // Shrink the size. let new_size = pre_offset.align_up(BLOCK_SIZE); - self.page_cache.resize(new_size)?; + self.page_cache.resize(new_size, self.page_cache.size())?; pre_entry_item.set_record_len(new_size - pre_offset); self.offset = pre_offset; self.write_header_only(&pre_entry_item.header)?; @@ -566,7 +565,7 @@ impl<'a> DirEntryWriter<'a> { let name_buf = &mut self.name_buf.as_mut().unwrap()[..name_len]; let offset = item.offset + DirEntry::HEADER_LEN; - self.page_cache.pages().read_bytes(offset, name_buf)?; + self.page_cache.read_bytes(offset, name_buf)?; Ok(name_buf) } diff --git a/kernel/src/fs/ext2/inode.rs b/kernel/src/fs/ext2/inode.rs index 3fdfb5c89..67367f67f 100644 --- a/kernel/src/fs/ext2/inode.rs +++ b/kernel/src/fs/ext2/inode.rs @@ -23,8 +23,8 @@ use crate::{ path::{is_dot, is_dot_or_dotdot, is_dotdot}, pipe::Pipe, utils::{ - Extension, FallocMode, Inode as _, InodeMode, Metadata, Permission, XattrName, - XattrNamespace, XattrSetFlags, + Extension, FallocMode, Inode as _, InodeMode, LockedCachePage, Metadata, Permission, + XattrName, XattrNamespace, XattrSetFlags, }, }, process::{Gid, Uid, posix_thread::AsPosixThread}, @@ -99,7 +99,7 @@ impl Inode { } pub fn page_cache(&self) -> Arc { - self.inner.read().page_cache.pages().clone() + self.inner.read().page_cache.clone() } pub fn metadata(&self) -> Metadata { @@ -976,7 +976,7 @@ impl InodeInner { let num_page_bytes = desc.num_page_bytes(); let inode_impl = InodeImpl::new(desc, weak_self, fs); Self { - page_cache: PageCache::with_capacity( + page_cache: PageCacheOps::with_capacity( num_page_bytes, Arc::downgrade(&inode_impl.block_manager) as _, ) @@ -986,7 +986,8 @@ impl InodeInner { } pub fn resize(&mut self, new_size: usize) -> Result<()> { - self.page_cache.resize(new_size)?; + self.page_cache + .resize(new_size, self.inode_impl.file_size())?; self.inode_impl.resize(new_size)?; Ok(()) } @@ -999,7 +1000,7 @@ impl InodeInner { (start, end - start) }; - self.page_cache.pages().read(offset, writer)?; + self.page_cache.read(offset, writer)?; Ok(read_len) } @@ -1016,7 +1017,7 @@ impl InodeInner { if read_len == 0 { return Ok(read_len); } - self.page_cache.discard_range(offset..offset + read_len); + self.page_cache.discard_range(offset..offset + read_len)?; let start_bid = Bid::from_offset(offset).to_raw() as Ext2Bid; let buf_nblocks = read_len / BLOCK_SIZE; @@ -1028,15 +1029,16 @@ impl InodeInner { pub fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result { let write_len = reader.remain(); - self.page_cache.pages().write(offset, reader)?; + self.page_cache.write(offset, reader)?; Ok(write_len) } pub fn extend_write_at(&mut self, offset: usize, reader: &mut VmReader) -> Result { let write_len = reader.remain(); let new_size = offset + write_len; - self.page_cache.resize(new_size.align_up(BLOCK_SIZE))?; - self.page_cache.pages().write(offset, reader)?; + self.page_cache + .resize(new_size.align_up(BLOCK_SIZE), self.inode_impl.file_size())?; + self.page_cache.write(offset, reader)?; self.inode_impl.resize(new_size)?; Ok(write_len) } @@ -1049,7 +1051,7 @@ impl InodeInner { let start = offset.min(file_size); let end = end_offset.min(file_size); - self.page_cache.discard_range(start..end); + self.page_cache.discard_range(start..end)?; if end_offset > file_size { self.inode_impl.resize(end_offset)?; @@ -1068,12 +1070,14 @@ impl InodeInner { return self.inode_impl.write_fast_link(target); } - self.page_cache.resize(target.len())?; - self.page_cache.pages().write_bytes(0, target.as_bytes())?; let file_size = self.inode_impl.file_size(); if file_size != target.len() { + self.page_cache.resize(target.len(), file_size)?; self.inode_impl.resize(target.len())?; } + + self.page_cache.write_bytes(0, target.as_bytes())?; + Ok(()) } @@ -1084,9 +1088,7 @@ impl InodeInner { } let mut symlink = vec![0u8; file_size]; - self.page_cache - .pages() - .read_bytes(0, symlink.as_mut_slice())?; + self.page_cache.read_bytes(0, symlink.as_mut_slice())?; Ok(String::from_utf8(symlink)?) } @@ -1125,7 +1127,7 @@ impl InodeInner { )?; let file_size = self.file_size(); - let page_cache_size = self.page_cache.pages().size(); + let page_cache_size = self.page_cache.size(); if page_cache_size > file_size { self.inode_impl.resize(page_cache_size)?; } @@ -1141,7 +1143,7 @@ impl InodeInner { pub fn remove_entry_at(&mut self, name: &str, offset: usize) -> Result<()> { let removed_entry = DirEntryWriter::new(&self.page_cache, offset).remove_entry(name)?; let file_size = self.file_size(); - let page_cache_size = self.page_cache.pages().size(); + let page_cache_size = self.page_cache.size(); if page_cache_size < file_size { self.inode_impl.resize(page_cache_size)?; } @@ -1154,7 +1156,7 @@ impl InodeInner { pub fn rename_entry_at(&mut self, old_name: &str, new_name: &str, offset: usize) -> Result<()> { DirEntryWriter::new(&self.page_cache, offset).rename_entry(old_name, new_name)?; let file_size = self.file_size(); - let page_cache_size = self.page_cache.pages().size(); + let page_cache_size = self.page_cache.size(); if page_cache_size != file_size { self.inode_impl.resize(page_cache_size)?; } @@ -1172,7 +1174,7 @@ impl InodeInner { pub fn sync_data(&self) -> Result<()> { // Writes back the data in page cache. let file_size = self.file_size(); - self.page_cache.evict_range(0..file_size)?; + self.page_cache.flush_range(0..file_size)?; Ok(()) } } @@ -1828,7 +1830,7 @@ impl InodeImpl { writer: &mut VmWriter, ) -> Result; pub fn read_blocks(&self, bid: Ext2Bid, nblocks: usize, writer: &mut VmWriter) -> Result<()>; - pub fn read_block_async(&self, bid: Ext2Bid, frame: &CachePage) -> Result; + pub fn read_block_async(&self, bid: Ext2Bid, frame: LockedCachePage) -> Result; pub fn write_blocks_async( &self, bid: Ext2Bid, @@ -1836,7 +1838,7 @@ impl InodeImpl { reader: &mut VmReader, ) -> Result; pub fn write_blocks(&self, bid: Ext2Bid, nblocks: usize, reader: &mut VmReader) -> Result<()>; - pub fn write_block_async(&self, bid: Ext2Bid, frame: &CachePage) -> Result; + pub fn write_block_async(&self, bid: Ext2Bid, frame: LockedCachePage) -> Result; } /// Manages the inode blocks and block I/O operations. @@ -1965,12 +1967,12 @@ impl InodeBlockManager { } impl PageCacheBackend for InodeBlockManager { - fn read_page_async(&self, idx: usize, frame: &CachePage) -> Result { + fn read_page_async(&self, idx: usize, frame: LockedCachePage) -> Result { let bid = idx as Ext2Bid; self.read_block_async(bid, frame) } - fn write_page_async(&self, idx: usize, frame: &CachePage) -> Result { + fn write_page_async(&self, idx: usize, frame: LockedCachePage) -> Result { let bid = idx as Ext2Bid; self.write_block_async(bid, frame) } diff --git a/kernel/src/fs/ext2/prelude.rs b/kernel/src/fs/ext2/prelude.rs index 5556782d3..deec3c710 100644 --- a/kernel/src/fs/ext2/prelude.rs +++ b/kernel/src/fs/ext2/prelude.rs @@ -19,7 +19,7 @@ pub(super) use ostd::{ pub(super) use super::utils::{Dirty, IsPowerOf}; pub(super) use crate::{ fs::utils::{ - CStr256, CachePage, DirentVisitor, InodeType, PageCache, PageCacheBackend, Str16, Str64, + CStr256, DirentVisitor, InodeType, PageCache, PageCacheBackend, PageCacheOps, Str16, Str64, }, prelude::*, time::UnixTime, diff --git a/kernel/src/fs/ramfs/fs.rs b/kernel/src/fs/ramfs/fs.rs index 725ccc2fd..b33f57e9f 100644 --- a/kernel/src/fs/ramfs/fs.rs +++ b/kernel/src/fs/ramfs/fs.rs @@ -6,14 +6,10 @@ use core::{ }; use align_ext::AlignExt; -use aster_block::bio::BioWaiter; use aster_util::slot_vec::SlotVec; use device_id::DeviceId; use hashbrown::HashMap; -use ostd::{ - mm::{HasSize, io_util::HasVmReaderWriter}, - sync::{PreemptDisabled, RwLockWriteGuard}, -}; +use ostd::sync::{PreemptDisabled, RwLockWriteGuard}; use super::{memfd::MemfdInode, xattr::RamXattr, *}; use crate::{ @@ -25,16 +21,16 @@ use crate::{ pipe::Pipe, registry::{FsProperties, FsType}, utils::{ - AccessMode, CStr256, CachePage, DirentVisitor, Extension, FallocMode, FileSystem, + AccessMode, CStr256, DirentVisitor, Extension, FallocMode, FileSystem, FsEventSubscriberStats, FsFlags, Inode, InodeIo, InodeMode, InodeType, Metadata, - MknodType, PageCache, PageCacheBackend, Permission, StatusFlags, SuperBlock, - SymbolicLink, XattrName, XattrNamespace, XattrSetFlags, mkmod, + MknodType, PageCache, PageCacheOps, Permission, StatusFlags, SuperBlock, SymbolicLink, + XattrName, XattrNamespace, XattrSetFlags, mkmod, }, }, prelude::*, process::{Gid, Uid}, time::clocks::RealTimeCoarseClock, - vm::vmo::Vmo, + vm::vmo::{Vmo, VmoFlags, VmoOptions}, }; /// A volatile file system whose data and metadata exists only in memory. @@ -136,8 +132,13 @@ impl Inner { Self::Dir(RwLock::new(DirEntry::new(this, parent))) } - pub(self) fn new_file(this: Weak) -> Self { - Self::File(PageCache::new(this).unwrap()) + pub(self) fn new_file() -> Self { + Self::File( + VmoOptions::new(0) + .flags(VmoFlags::RESIZABLE) + .alloc() + .unwrap(), + ) } pub(self) fn new_symlink() -> Self { @@ -160,8 +161,13 @@ impl Inner { Self::NamedPipe(Pipe::new()) } - pub(self) fn new_file_in_memfd(this: Weak) -> Self { - Self::File(PageCache::new(this).unwrap()) + pub(self) fn new_file_in_memfd() -> Self { + Self::File( + VmoOptions::new(0) + .flags(VmoFlags::RESIZABLE) + .alloc() + .unwrap(), + ) } fn as_direntry(&self) -> Option<&RwLock> { @@ -456,7 +462,7 @@ impl RamInode { fn new_file(fs: &Arc, mode: InodeMode, uid: Uid, gid: Gid) -> Arc { Arc::new_cyclic(|weak_self| RamInode { - inner: Inner::new_file(weak_self.clone()), + inner: Inner::new_file(), metadata: SpinLock::new(InodeMeta::new(mode, uid, gid)), ino: fs.alloc_id(), typ: InodeType::File, @@ -475,7 +481,7 @@ impl RamInode { gid: Gid, ) -> Self { Self { - inner: Inner::new_file_in_memfd(weak_self.clone()), + inner: Inner::new_file_in_memfd(), metadata: SpinLock::new(InodeMeta::new(mode, uid, gid)), ino: weak_self.as_ptr() as u64, typ: InodeType::File, @@ -566,23 +572,6 @@ impl RamInode { } } -impl PageCacheBackend for RamInode { - fn read_page_async(&self, _idx: usize, frame: &CachePage) -> Result { - // Initially, any block/page in a RamFs inode contains all zeros - frame.writer().fill_zeros(frame.size()); - Ok(BioWaiter::new()) - } - - fn write_page_async(&self, _idx: usize, _frame: &CachePage) -> Result { - // do nothing - Ok(BioWaiter::new()) - } - - fn npages(&self) -> usize { - self.metadata.lock().blocks - } -} - impl InodeIo for RamInode { fn read_at( &self, @@ -598,7 +587,7 @@ impl InodeIo for RamInode { let end = file_size.min(offset + writer.avail()); (start, end - start) }; - page_cache.pages().read(offset, writer)?; + page_cache.read(offset, writer)?; read_len } _ => return_errno_with_message!(Errno::EISDIR, "read is not supported"), @@ -626,9 +615,9 @@ impl InodeIo for RamInode { let should_expand_size = new_size > file_size; let new_size_aligned = new_size.align_up(BLOCK_SIZE); if should_expand_size { - page_cache.resize(new_size_aligned)?; + page_cache.resize(new_size_aligned, file_size)?; } - page_cache.pages().write(offset, reader)?; + page_cache.write(offset, reader)?; let now = now(); let mut inode_meta = self.metadata.lock(); @@ -648,9 +637,7 @@ impl InodeIo for RamInode { impl Inode for RamInode { fn page_cache(&self) -> Option> { - self.inner - .as_file() - .map(|page_cache| page_cache.pages().clone()) + self.inner.as_file().cloned() } fn size(&self) -> usize { @@ -671,7 +658,7 @@ impl Inode for RamInode { } let page_cache = self.inner.as_file().unwrap(); - page_cache.resize(new_size)?; + page_cache.resize(new_size, file_size)?; let now = now(); let mut inode_meta = self.metadata.lock(); diff --git a/kernel/src/fs/ramfs/memfd.rs b/kernel/src/fs/ramfs/memfd.rs index 675bd25a1..95309c0db 100644 --- a/kernel/src/fs/ramfs/memfd.rs +++ b/kernel/src/fs/ramfs/memfd.rs @@ -6,7 +6,6 @@ use alloc::format; use core::time::Duration; use align_ext::AlignExt; -use aster_block::bio::BioWaiter; use aster_rights::Rights; use inherit_methods_macro::inherit_methods; use spin::Once; @@ -18,9 +17,8 @@ use crate::{ path::{Mount, Path}, tmpfs::TmpFs, utils::{ - AccessMode, CachePage, Extension, FallocMode, FileSystem, Inode, InodeIo, InodeMode, - InodeType, Metadata, PageCacheBackend, StatusFlags, XattrName, XattrNamespace, - XattrSetFlags, mkmod, + AccessMode, Extension, FallocMode, FileSystem, Inode, InodeIo, InodeMode, InodeType, + Metadata, StatusFlags, XattrName, XattrNamespace, XattrSetFlags, mkmod, }, }, prelude::*, @@ -91,13 +89,6 @@ impl MemfdInode { } } -#[inherit_methods(from = "self.inode")] -impl PageCacheBackend for MemfdInode { - fn read_page_async(&self, idx: usize, frame: &CachePage) -> Result; - fn write_page_async(&self, idx: usize, frame: &CachePage) -> Result; - fn npages(&self) -> usize; -} - #[inherit_methods(from = "self.inode")] impl InodeIo for MemfdInode { fn read_at( diff --git a/kernel/src/fs/utils/mod.rs b/kernel/src/fs/utils/mod.rs index 7beb77599..32945c242 100644 --- a/kernel/src/fs/utils/mod.rs +++ b/kernel/src/fs/utils/mod.rs @@ -19,7 +19,11 @@ pub use inode_ext::InodeExt; pub use inode_mode::InodeMode; pub(crate) use inode_mode::{chmod, mkmod, perms_to_mask, who_and_perms_to_mask, who_to_mask}; pub use open_args::OpenArgs; -pub use page_cache::{CachePage, PageCache, PageCacheBackend}; +#[expect(unused_imports)] +pub use page_cache::{ + CachePage, CachePageExt, CachePageMeta, LockedCachePage, PageCache, PageCacheBackend, + PageCacheOps, PageState, +}; #[cfg(ktest)] pub use random_test::{generate_random_operation, new_fs_in_memory}; pub use range_lock::{FileRange, OFFSET_MAX, RangeLockItem, RangeLockList, RangeLockType}; diff --git a/kernel/src/vdso.rs b/kernel/src/vdso.rs index 8a6dc0bff..1147c7e6b 100644 --- a/kernel/src/vdso.rs +++ b/kernel/src/vdso.rs @@ -262,7 +262,7 @@ impl Vdso { Self { data: SpinLock::new(vdso_data), vmo: vdso_vmo, - data_frame, + data_frame: data_frame.into(), } } diff --git a/kernel/src/vm/vmar/vm_mapping.rs b/kernel/src/vm/vmar/vm_mapping.rs index a1995de35..8dd70da60 100644 --- a/kernel/src/vm/vmar/vm_mapping.rs +++ b/kernel/src/vm/vmar/vm_mapping.rs @@ -22,14 +22,14 @@ use super::{RssType, Vmar, interval_set::Interval, util::is_intersected, vmar_im use crate::{ fs::{ path::{Path, PathResolver}, - utils::Inode, + utils::{CachePage, Inode}, }, prelude::*, process::LockedHeap, thread::exception::PageFaultInfo, vm::{ perms::VmPerms, - vmo::{CommitFlags, Vmo, VmoCommitError}, + vmo::{Vmo, VmoCommitError}, }, }; @@ -434,13 +434,18 @@ impl VmMapping { let (frame, is_readonly) = match self.prepare_page(page_aligned_addr, is_write) { Ok((frame, is_readonly)) => (frame, is_readonly), - Err(VmoCommitError::Err(e)) => return Err(e), - Err(VmoCommitError::NeedIo(index)) => { + Err( + VmoCommitError::NeedIo(index) | VmoCommitError::WaitUntilInit(index, _), + ) => { drop(cursor); drop(preempt_guard); - self.vmo().unwrap().commit_on(index, CommitFlags::empty())?; + self.vmo().unwrap().commit_on(index)?; continue 'retry; } + Err(VmoCommitError::Err(e)) => return Err(e), + Err(_) => { + unreachable!("unexpected VmoCommitError"); + } }; let vm_perms = { @@ -549,38 +554,42 @@ impl VmMapping { let mut cursor = vm_space.cursor_mut(&preempt_guard, &(start_addr..end_addr))?; let rss_delta_ref = &mut rss_delta; - let operate = - move |commit_fn: &mut dyn FnMut() - -> core::result::Result| { - if let (_, None) = cursor.query().unwrap() { - // We regard all the surrounding pages as accessed, no matter - // if it is really so. Then the hardware won't bother to update - // the accessed bit of the page table on following accesses. - let page_flags = PageFlags::from(vm_perms) | PageFlags::ACCESSED; - let page_prop = PageProperty::new_user(page_flags, CachePolicy::Writeback); - let frame = commit_fn()?; - cursor.map(frame, page_prop); - rss_delta_ref.add(self.rss_type(), 1); - } else { - let next_addr = cursor.virt_addr() + PAGE_SIZE; - if next_addr < end_addr { - let _ = cursor.jump(next_addr); - } + let operate = move |commit_fn: &mut dyn FnMut() -> core::result::Result< + (usize, CachePage), + VmoCommitError, + >| { + if let (_, None) = cursor.query().unwrap() { + // We regard all the surrounding pages as accessed, no matter + // if it is really so. Then the hardware won't bother to update + // the accessed bit of the page table on following accesses. + let page_flags = PageFlags::from(vm_perms) | PageFlags::ACCESSED; + let page_prop = PageProperty::new_user(page_flags, CachePolicy::Writeback); + let (_, frame) = commit_fn()?; + cursor.map(frame.into(), page_prop); + rss_delta_ref.add(self.rss_type(), 1); + } else { + let next_addr = cursor.virt_addr() + PAGE_SIZE; + if next_addr < end_addr { + let _ = cursor.jump(next_addr); } - Ok(()) - }; + } + Ok(()) + }; let start_offset = start_addr - self.map_to_addr; let end_offset = end_addr - self.map_to_addr; match vmo.try_operate_on_range(&(start_offset..end_offset), operate) { Ok(_) => return Ok(()), - Err(VmoCommitError::NeedIo(index)) => { + Err(VmoCommitError::NeedIo(index) | VmoCommitError::WaitUntilInit(index, _)) => { drop(preempt_guard); - vmo.commit_on(index, CommitFlags::empty())?; + vmo.commit_on(index)?; start_addr = (index * PAGE_SIZE - vmo.offset()) + self.map_to_addr; continue 'retry; } Err(VmoCommitError::Err(e)) => return Err(e), + Err(_) => { + unreachable!("unexpected VmoCommitError"); + } } } } @@ -833,15 +842,17 @@ impl MappedVmo { page_offset: usize, ) -> core::result::Result { debug_assert!(page_offset.is_multiple_of(PAGE_SIZE)); - self.vmo.try_commit_page(self.offset + page_offset) + self.vmo + .try_commit_page(self.offset + page_offset) + .map(|frame| frame.into()) } /// Commits a page at a specific page index. /// /// This method may involve I/O operations if the VMO needs to fetch /// a page from the underlying page cache. - pub fn commit_on(&self, page_idx: usize, commit_flags: CommitFlags) -> Result { - self.vmo.commit_on(page_idx, commit_flags) + pub fn commit_on(&self, page_idx: usize) -> Result { + self.vmo.commit_on(page_idx).map(|frame| frame.into()) } /// Traverses the indices within a specified range of a VMO sequentially. @@ -857,7 +868,7 @@ impl MappedVmo { ) -> core::result::Result<(), VmoCommitError> where F: FnMut( - &mut dyn FnMut() -> core::result::Result, + &mut dyn FnMut() -> core::result::Result<(usize, CachePage), VmoCommitError>, ) -> core::result::Result<(), VmoCommitError>, { let range = self.offset + range.start..self.offset + range.end; diff --git a/kernel/src/vm/vmo/options.rs b/kernel/src/vm/vmo/options.rs index 7d024e65c..aaac7dbbc 100644 --- a/kernel/src/vm/vmo/options.rs +++ b/kernel/src/vm/vmo/options.rs @@ -5,11 +5,14 @@ use core::sync::atomic::AtomicUsize; use align_ext::AlignExt; -use ostd::mm::{FrameAllocOptions, UFrame, USegment}; +use ostd::mm::{FrameAllocOptions, Segment}; use xarray::XArray; -use super::{Pager, Vmo, VmoFlags, WritableMappingStatus}; -use crate::prelude::*; +use super::{Vmo, VmoFlags, WritableMappingStatus}; +use crate::{ + fs::utils::{CachePage, CachePageMeta, PageCacheBackend}, + prelude::*, +}; /// Options for allocating a root VMO. /// @@ -38,7 +41,7 @@ use crate::prelude::*; pub struct VmoOptions { size: usize, flags: VmoFlags, - pager: Option>, + backend: Option>, } impl VmoOptions { @@ -50,7 +53,7 @@ impl VmoOptions { Self { size, flags: VmoFlags::empty(), - pager: None, + backend: None, } } @@ -65,8 +68,8 @@ impl VmoOptions { } /// Sets the pager of the VMO. - pub fn pager(mut self, pager: Arc) -> Self { - self.pager = Some(pager); + pub fn backend(mut self, backend: Weak) -> Self { + self.backend = Some(backend); self } } @@ -75,19 +78,26 @@ impl VmoOptions { /// Allocates the VMO according to the specified options. pub fn alloc(self) -> Result> { let VmoOptions { - size, flags, pager, .. + size, + flags, + backend, + .. } = self; - let vmo = alloc_vmo(size, flags, pager)?; + let vmo = alloc_vmo(size, flags, backend)?; Ok(Arc::new(vmo)) } } -fn alloc_vmo(size: usize, flags: VmoFlags, pager: Option>) -> Result { +fn alloc_vmo( + size: usize, + flags: VmoFlags, + backend: Option>, +) -> Result { let size = size.align_up(PAGE_SIZE); let pages = committed_pages_if_continuous(flags, size)?; let writable_mapping_status = WritableMappingStatus::default(); Ok(Vmo { - pager, + backend, flags, pages, size: AtomicUsize::new(size), @@ -95,11 +105,12 @@ fn alloc_vmo(size: usize, flags: VmoFlags, pager: Option>) -> Res }) } -fn committed_pages_if_continuous(flags: VmoFlags, size: usize) -> Result> { +fn committed_pages_if_continuous(flags: VmoFlags, size: usize) -> Result> { if flags.contains(VmoFlags::CONTIGUOUS) { // if the vmo is continuous, we need to allocate frames for the vmo let frames_num = size / PAGE_SIZE; - let segment: USegment = FrameAllocOptions::new().alloc_segment(frames_num)?.into(); + let segment: Segment = FrameAllocOptions::new() + .alloc_segment_with(frames_num, |_| CachePageMeta::default())?; let committed_pages = XArray::new(); let mut locked_pages = committed_pages.lock(); let mut cursor = locked_pages.cursor_mut(0); @@ -154,16 +165,18 @@ mod test { #[ktest] fn resize() { + use crate::fs::utils::PageCacheOps; + let vmo = VmoOptions::new(PAGE_SIZE) .flags(VmoFlags::RESIZABLE) .alloc() .unwrap(); vmo.write_val(10, &42u8).unwrap(); - vmo.resize(2 * PAGE_SIZE).unwrap(); + vmo.resize(2 * PAGE_SIZE, vmo.size()).unwrap(); assert_eq!(vmo.size(), 2 * PAGE_SIZE); assert_eq!(vmo.read_val::(10).unwrap(), 42); vmo.write_val(PAGE_SIZE + 20, &123u8).unwrap(); - vmo.resize(PAGE_SIZE).unwrap(); + vmo.resize(PAGE_SIZE, vmo.size()).unwrap(); assert_eq!(vmo.read_val::(10).unwrap(), 42); } } diff --git a/kernel/src/vm/vmo/pager.rs b/kernel/src/vm/vmo/pager.rs deleted file mode 100644 index 8fc11d2fb..000000000 --- a/kernel/src/vm/vmo/pager.rs +++ /dev/null @@ -1,58 +0,0 @@ -// SPDX-License-Identifier: MPL-2.0 - -use ostd::mm::UFrame; - -use crate::prelude::*; - -/// Pagers provide frame to a VMO. -/// -/// A `Pager` object can be attached to a VMO. Whenever the -/// VMO needs more frames (i.e., on commits), it will turn to the pager, -/// which should then provide frames whose data have been initialized properly. -/// Any time a frame is updated through the VMO, the VMO will -/// notify the attached pager that the frame has been updated. -/// Finally, when a frame is no longer needed (i.e., on decommits), -/// the frame pager will also be notified. -pub trait Pager: Send + Sync { - /// Ask the pager to provide a frame at a specified index. - /// - /// After a page of a VMO is committed, the VMO shall not call this method - /// again until the page is decommitted. But a robust implementation of - /// `Pager` should not rely on this behavior for its correctness; - /// instead, it should returns the _same_ frame. - /// - /// If a VMO page has been previously committed and decommited, - /// and is to be committed again, then the pager is free to return - /// whatever frame that may or may not be the same as the last time. - /// - /// It is up to the pager to decide the range of valid indices. - fn commit_page(&self, idx: usize) -> Result; - - /// Notify the pager that the frame at a specified index has been updated. - /// - /// Being aware of the updates allow the pager (e.g., an inode) to - /// know which pages are dirty and only write back the _dirty_ pages back - /// to disk. - /// - /// The VMO will not call this method for an uncommitted page. - /// But a robust implementation of `Pager` should not make - /// such an assumption for its correctness; instead, it should simply ignore the - /// call or return an error. - fn update_page(&self, idx: usize) -> Result<()>; - - /// Notify the pager that the frame at the specified index has been decommitted. - /// - /// Knowing that a frame is no longer needed, the pager (e.g., an inode) - /// can free the frame after writing back its data to the disk. - /// - /// The VMO will not call this method for an uncommitted page. - /// But a robust implementation of `Pager` should not make - /// such an assumption for its correctness; instead, it should simply ignore the - /// call or return an error. - fn decommit_page(&self, idx: usize) -> Result<()>; - - /// Ask the pager to provide a frame at a specified index. - /// Notify the pager that the frame will be fully overwritten soon, so pager can - /// choose not to initialize it. - fn commit_overwrite(&self, idx: usize) -> Result; -}