Modify some related usages of PageCache and VMO
This commit is contained in:
parent
610504e2e9
commit
22053aad99
|
|
@ -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::<ClusterID, ClusterID>::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<usize>) -> 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(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<usize> {
|
||||
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<Arc<Vmo>> {
|
||||
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<Arc<dyn Inode>> {
|
||||
|
|
|
|||
|
|
@ -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::<RawInode>(offset)
|
||||
.unwrap()
|
||||
self.raw_inodes_cache.read_val::<RawInode>(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(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<DirEntryItem> {
|
||||
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::<DirEntryHeader>(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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Vmo> {
|
||||
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<usize> {
|
||||
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<usize> {
|
||||
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<BioWaiter>;
|
||||
pub fn read_blocks(&self, bid: Ext2Bid, nblocks: usize, writer: &mut VmWriter) -> Result<()>;
|
||||
pub fn read_block_async(&self, bid: Ext2Bid, frame: &CachePage) -> Result<BioWaiter>;
|
||||
pub fn read_block_async(&self, bid: Ext2Bid, frame: LockedCachePage) -> Result<BioWaiter>;
|
||||
pub fn write_blocks_async(
|
||||
&self,
|
||||
bid: Ext2Bid,
|
||||
|
|
@ -1836,7 +1838,7 @@ impl InodeImpl {
|
|||
reader: &mut VmReader,
|
||||
) -> Result<BioWaiter>;
|
||||
pub fn write_blocks(&self, bid: Ext2Bid, nblocks: usize, reader: &mut VmReader) -> Result<()>;
|
||||
pub fn write_block_async(&self, bid: Ext2Bid, frame: &CachePage) -> Result<BioWaiter>;
|
||||
pub fn write_block_async(&self, bid: Ext2Bid, frame: LockedCachePage) -> Result<BioWaiter>;
|
||||
}
|
||||
|
||||
/// 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<BioWaiter> {
|
||||
fn read_page_async(&self, idx: usize, frame: LockedCachePage) -> Result<BioWaiter> {
|
||||
let bid = idx as Ext2Bid;
|
||||
self.read_block_async(bid, frame)
|
||||
}
|
||||
|
||||
fn write_page_async(&self, idx: usize, frame: &CachePage) -> Result<BioWaiter> {
|
||||
fn write_page_async(&self, idx: usize, frame: LockedCachePage) -> Result<BioWaiter> {
|
||||
let bid = idx as Ext2Bid;
|
||||
self.write_block_async(bid, frame)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<RamInode>) -> 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<MemfdInode>) -> 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<DirEntry>> {
|
||||
|
|
@ -456,7 +462,7 @@ impl RamInode {
|
|||
|
||||
fn new_file(fs: &Arc<RamFs>, mode: InodeMode, uid: Uid, gid: Gid) -> Arc<Self> {
|
||||
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<BioWaiter> {
|
||||
// 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<BioWaiter> {
|
||||
// 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<Arc<Vmo>> {
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -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<BioWaiter>;
|
||||
fn write_page_async(&self, idx: usize, frame: &CachePage) -> Result<BioWaiter>;
|
||||
fn npages(&self) -> usize;
|
||||
}
|
||||
|
||||
#[inherit_methods(from = "self.inode")]
|
||||
impl InodeIo for MemfdInode {
|
||||
fn read_at(
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -262,7 +262,7 @@ impl Vdso {
|
|||
Self {
|
||||
data: SpinLock::new(vdso_data),
|
||||
vmo: vdso_vmo,
|
||||
data_frame,
|
||||
data_frame: data_frame.into(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,17 +554,18 @@ 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<UFrame, VmoCommitError>| {
|
||||
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, page_prop);
|
||||
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;
|
||||
|
|
@ -574,13 +580,16 @@ impl VmMapping {
|
|||
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<UFrame, VmoCommitError> {
|
||||
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<UFrame> {
|
||||
self.vmo.commit_on(page_idx, commit_flags)
|
||||
pub fn commit_on(&self, page_idx: usize) -> Result<UFrame> {
|
||||
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<UFrame, VmoCommitError>,
|
||||
&mut dyn FnMut() -> core::result::Result<(usize, CachePage), VmoCommitError>,
|
||||
) -> core::result::Result<(), VmoCommitError>,
|
||||
{
|
||||
let range = self.offset + range.start..self.offset + range.end;
|
||||
|
|
|
|||
|
|
@ -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<Arc<dyn Pager>>,
|
||||
backend: Option<Weak<dyn PageCacheBackend>>,
|
||||
}
|
||||
|
||||
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<dyn Pager>) -> Self {
|
||||
self.pager = Some(pager);
|
||||
pub fn backend(mut self, backend: Weak<dyn PageCacheBackend>) -> 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<Arc<Vmo>> {
|
||||
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<Arc<dyn Pager>>) -> Result<Vmo> {
|
||||
fn alloc_vmo(
|
||||
size: usize,
|
||||
flags: VmoFlags,
|
||||
backend: Option<Weak<dyn PageCacheBackend>>,
|
||||
) -> Result<Vmo> {
|
||||
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<Arc<dyn Pager>>) -> Res
|
|||
})
|
||||
}
|
||||
|
||||
fn committed_pages_if_continuous(flags: VmoFlags, size: usize) -> Result<XArray<UFrame>> {
|
||||
fn committed_pages_if_continuous(flags: VmoFlags, size: usize) -> Result<XArray<CachePage>> {
|
||||
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<CachePageMeta> = 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::<u8>(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::<u8>(10).unwrap(), 42);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<UFrame>;
|
||||
|
||||
/// 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<UFrame>;
|
||||
}
|
||||
Loading…
Reference in New Issue