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},
|
exfat::{constants::*, inode::Ino},
|
||||||
registry::{FsProperties, FsType},
|
registry::{FsProperties, FsType},
|
||||||
utils::{
|
utils::{
|
||||||
CachePage, FileSystem, FsEventSubscriberStats, FsFlags, Inode, PageCache,
|
FileSystem, FsEventSubscriberStats, FsFlags, Inode, LockedCachePage, PageCache,
|
||||||
PageCacheBackend, SuperBlock,
|
PageCacheBackend, PageCacheOps, SuperBlock,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
|
@ -83,7 +83,7 @@ impl ExfatFs {
|
||||||
fat_cache: RwLock::new(LruCache::<ClusterID, ClusterID>::new(
|
fat_cache: RwLock::new(LruCache::<ClusterID, ClusterID>::new(
|
||||||
NonZeroUsize::new(FAT_LRU_CACHE_SIZE).unwrap(),
|
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(()),
|
mutex: Mutex::new(()),
|
||||||
fs_event_subscriber_stats: FsEventSubscriberStats::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<()> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn write_meta_at(&self, offset: usize, buf: &[u8]) -> Result<()> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn read_meta_at(&self, offset: usize, buf: &mut [u8]) -> Result<()> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -422,7 +422,7 @@ impl FileSystem for ExfatFs {
|
||||||
for inode in self.inodes.read().values() {
|
for inode in self.inodes.read().values() {
|
||||||
inode.sync_all()?;
|
inode.sync_all()?;
|
||||||
}
|
}
|
||||||
self.meta_cache.evict_range(0..self.fs_size())?;
|
self.meta_cache.flush_range(0..self.fs_size())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,9 @@ use crate::{
|
||||||
exfat::{dentry::ExfatDentryIterator, fat::ExfatChain, fs::ExfatFs},
|
exfat::{dentry::ExfatDentryIterator, fat::ExfatChain, fs::ExfatFs},
|
||||||
path::{is_dot, is_dot_or_dotdot, is_dotdot},
|
path::{is_dot, is_dot_or_dotdot, is_dotdot},
|
||||||
utils::{
|
utils::{
|
||||||
CachePage, DirentVisitor, Extension, Inode, InodeIo, InodeMode, InodeType, Metadata,
|
DirentVisitor, Extension, Inode, InodeIo, InodeMode, InodeType, LockedCachePage,
|
||||||
MknodType, PageCache, PageCacheBackend, StatusFlags, SymbolicLink, mkmod,
|
Metadata, MknodType, PageCache, PageCacheBackend, PageCacheOps, StatusFlags,
|
||||||
|
SymbolicLink, mkmod,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
|
@ -254,7 +255,7 @@ impl ExfatInodeInner {
|
||||||
return Ok((0, 0));
|
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_inodes = 0;
|
||||||
let mut sub_dirs = 0;
|
let mut sub_dirs = 0;
|
||||||
for dentry_result in iterator {
|
for dentry_result in iterator {
|
||||||
|
|
@ -357,7 +358,7 @@ impl ExfatInodeInner {
|
||||||
|
|
||||||
page_cache.write_bytes(start_off, &bytes)?;
|
page_cache.write_bytes(start_off, &bytes)?;
|
||||||
if sync {
|
if sync {
|
||||||
page_cache.decommit(start_off..start_off + bytes.len())?;
|
page_cache.flush_range(start_off..start_off + bytes.len())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -383,7 +384,7 @@ impl ExfatInodeInner {
|
||||||
let fs = self.fs();
|
let fs = self.fs();
|
||||||
let cluster_size = fs.cluster_size();
|
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 dir_read = 0;
|
||||||
let mut current_off = offset;
|
let mut current_off = offset;
|
||||||
|
|
@ -590,7 +591,7 @@ impl ExfatInodeInner {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sync_data(&self, fs_guard: &MutexGuard<()>) -> Result<()> {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -634,7 +635,7 @@ impl ExfatInode {
|
||||||
let end = file_size.min(offset + writer.avail());
|
let end = file_size.min(offset + writer.avail());
|
||||||
(start, end - start)
|
(start, end - start)
|
||||||
};
|
};
|
||||||
inner.page_cache.pages().read(read_off, writer)?;
|
inner.page_cache.read(read_off, writer)?;
|
||||||
|
|
||||||
inner.upgrade().update_atime()?;
|
inner.upgrade().update_atime()?;
|
||||||
Ok(read_len)
|
Ok(read_len)
|
||||||
|
|
@ -663,7 +664,7 @@ impl ExfatInode {
|
||||||
|
|
||||||
inner
|
inner
|
||||||
.page_cache
|
.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);
|
let bio_segment = BioSegment::alloc(1, BioDirection::FromDevice);
|
||||||
|
|
||||||
|
|
@ -709,14 +710,14 @@ impl ExfatInode {
|
||||||
if new_size > file_allocated_size {
|
if new_size > file_allocated_size {
|
||||||
inner.resize(new_size, &fs_guard)?;
|
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)
|
new_size.max(file_size)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Locks released here, so that file write can be parallelized.
|
// Locks released here, so that file write can be parallelized.
|
||||||
let inner = self.inner.upread();
|
let inner = self.inner.upread();
|
||||||
inner.page_cache.pages().write(offset, reader)?;
|
inner.page_cache.write(offset, reader)?;
|
||||||
|
|
||||||
// Update timestamps and size.
|
// Update timestamps and size.
|
||||||
{
|
{
|
||||||
|
|
@ -754,7 +755,7 @@ impl ExfatInode {
|
||||||
|
|
||||||
let start = offset.min(file_size);
|
let start = offset.min(file_size);
|
||||||
let end = end_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 new_size = {
|
||||||
let mut inner = inner.upgrade();
|
let mut inner = inner.upgrade();
|
||||||
|
|
@ -764,7 +765,7 @@ impl ExfatInode {
|
||||||
if end_offset > file_allocated_size {
|
if end_offset > file_allocated_size {
|
||||||
inner.resize(end_offset, &fs_guard)?;
|
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)
|
file_size.max(end_offset)
|
||||||
};
|
};
|
||||||
|
|
@ -813,8 +814,9 @@ impl ExfatInode {
|
||||||
let inner = self.inner.write();
|
let inner = self.inner.write();
|
||||||
let fs = inner.fs();
|
let fs = inner.fs();
|
||||||
let fs_guard = fs.lock();
|
let fs_guard = fs.lock();
|
||||||
self.inner.write().resize(0, &fs_guard)?;
|
let mut inner = self.inner.write();
|
||||||
self.inner.read().page_cache.resize(0)?;
|
inner.resize(0, &fs_guard)?;
|
||||||
|
inner.page_cache.resize(0, inner.size)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -845,7 +847,6 @@ impl ExfatInode {
|
||||||
let size = root_chain.num_clusters() as usize * sb.cluster_size as usize;
|
let size = root_chain.num_clusters() as usize * sb.cluster_size as usize;
|
||||||
|
|
||||||
let name = ExfatName::new();
|
let name = ExfatName::new();
|
||||||
|
|
||||||
let inode = Arc::new_cyclic(|weak_self| ExfatInode {
|
let inode = Arc::new_cyclic(|weak_self| ExfatInode {
|
||||||
inner: RwMutex::new(ExfatInodeInner {
|
inner: RwMutex::new(ExfatInodeInner {
|
||||||
ino: EXFAT_ROOT_INO,
|
ino: EXFAT_ROOT_INO,
|
||||||
|
|
@ -866,7 +867,7 @@ impl ExfatInode {
|
||||||
is_deleted: false,
|
is_deleted: false,
|
||||||
parent_hash: 0,
|
parent_hash: 0,
|
||||||
fs: fs_weak,
|
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(),
|
extension: Extension::new(),
|
||||||
});
|
});
|
||||||
|
|
@ -976,7 +977,7 @@ impl ExfatInode {
|
||||||
is_deleted: false,
|
is_deleted: false,
|
||||||
parent_hash,
|
parent_hash,
|
||||||
fs: fs_weak,
|
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(),
|
extension: Extension::new(),
|
||||||
});
|
});
|
||||||
|
|
@ -1019,8 +1020,7 @@ impl ExfatInode {
|
||||||
fn find_empty_dentries(&self, num_dentries: usize, fs_guard: &MutexGuard<()>) -> Result<usize> {
|
fn find_empty_dentries(&self, num_dentries: usize, fs_guard: &MutexGuard<()>) -> Result<usize> {
|
||||||
let inner = self.inner.upread();
|
let inner = self.inner.upread();
|
||||||
|
|
||||||
let dentry_iterator =
|
let dentry_iterator = ExfatDentryIterator::new(&inner.page_cache, 0, Some(inner.size))?;
|
||||||
ExfatDentryIterator::new(inner.page_cache.pages(), 0, Some(inner.size))?;
|
|
||||||
|
|
||||||
let mut contiguous_unused = 0;
|
let mut contiguous_unused = 0;
|
||||||
let mut entry_id = 0;
|
let mut entry_id = 0;
|
||||||
|
|
@ -1063,15 +1063,16 @@ impl ExfatInode {
|
||||||
inner.size_allocated = new_size_allocated;
|
inner.size_allocated = new_size_allocated;
|
||||||
inner.size = 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();
|
let inner = self.inner.read();
|
||||||
|
|
||||||
// We need to write unused dentries (i.e. 0) to page cache.
|
// We need to write unused dentries (i.e. 0) to page cache.
|
||||||
inner
|
inner
|
||||||
.page_cache
|
.page_cache
|
||||||
.pages()
|
.fill_zeros(old_size_allocated..new_size_allocated)?;
|
||||||
.clear(old_size_allocated..new_size_allocated)?;
|
|
||||||
|
|
||||||
Ok(entry_id)
|
Ok(entry_id)
|
||||||
}
|
}
|
||||||
|
|
@ -1106,7 +1107,6 @@ impl ExfatInode {
|
||||||
let inner = self.inner.upread();
|
let inner = self.inner.upread();
|
||||||
inner
|
inner
|
||||||
.page_cache
|
.page_cache
|
||||||
.pages()
|
|
||||||
.write_bytes(start_off, &dentry_set.to_le_bytes())?;
|
.write_bytes(start_off, &dentry_set.to_le_bytes())?;
|
||||||
|
|
||||||
let mut inner = inner.upgrade();
|
let mut inner = inner.upgrade();
|
||||||
|
|
@ -1144,11 +1144,7 @@ impl ExfatInode {
|
||||||
let fs = self.inner.read().fs();
|
let fs = self.inner.read().fs();
|
||||||
let mut buf = vec![0; len];
|
let mut buf = vec![0; len];
|
||||||
|
|
||||||
self.inner
|
self.inner.read().page_cache.read_bytes(offset, &mut buf)?;
|
||||||
.read()
|
|
||||||
.page_cache
|
|
||||||
.pages()
|
|
||||||
.read_bytes(offset, &mut buf)?;
|
|
||||||
|
|
||||||
let num_dentry = len / DENTRY_SIZE;
|
let num_dentry = len / DENTRY_SIZE;
|
||||||
|
|
||||||
|
|
@ -1166,11 +1162,7 @@ impl ExfatInode {
|
||||||
buf[buf_offset] &= 0x7F;
|
buf[buf_offset] &= 0x7F;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.inner
|
self.inner.read().page_cache.write_bytes(offset, &buf)?;
|
||||||
.read()
|
|
||||||
.page_cache
|
|
||||||
.pages()
|
|
||||||
.write_bytes(offset, &buf)?;
|
|
||||||
|
|
||||||
// FIXME: We must make sure that there are no spare tailing clusters in a directory.
|
// FIXME: We must make sure that there are no spare tailing clusters in a directory.
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -1242,8 +1234,9 @@ impl ExfatInode {
|
||||||
let is_dir = inode.inner.read().inode_type.is_directory();
|
let is_dir = inode.inner.read().inode_type.is_directory();
|
||||||
if delete_contents {
|
if delete_contents {
|
||||||
if is_dir {
|
if is_dir {
|
||||||
inode.inner.write().resize(0, fs_guard)?;
|
let mut inner = inode.inner.write();
|
||||||
inode.inner.read().page_cache.resize(0)?;
|
inner.resize(0, fs_guard)?;
|
||||||
|
inner.page_cache.resize(0, inner.size)?;
|
||||||
}
|
}
|
||||||
// Set the delete flag.
|
// Set the delete flag.
|
||||||
inode.inner.write().is_deleted = true;
|
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.
|
// We will delay updating the page_cache size when enlarging an inode until the real write.
|
||||||
if new_size < file_size {
|
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.
|
// Sync this inode since size has changed.
|
||||||
|
|
@ -1449,7 +1442,7 @@ impl Inode for ExfatInode {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn page_cache(&self) -> Option<Arc<Vmo>> {
|
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>> {
|
fn create(&self, name: &str, type_: InodeType, mode: InodeMode) -> Result<Arc<dyn Inode>> {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use super::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
super_block::SuperBlock,
|
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
|
/// 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.
|
/// the amount of head seeking when reading a large amount of consecutive data.
|
||||||
|
|
@ -91,7 +91,7 @@ impl BlockGroup {
|
||||||
};
|
};
|
||||||
|
|
||||||
let raw_inodes_cache =
|
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 {
|
Ok(Self {
|
||||||
idx,
|
idx,
|
||||||
|
|
@ -134,10 +134,7 @@ impl BlockGroup {
|
||||||
let fs = self.fs();
|
let fs = self.fs();
|
||||||
let raw_inode = {
|
let raw_inode = {
|
||||||
let offset = (inode_idx as usize) * fs.inode_size();
|
let offset = (inode_idx as usize) * fs.inode_size();
|
||||||
self.raw_inodes_cache
|
self.raw_inodes_cache.read_val::<RawInode>(offset).unwrap()
|
||||||
.pages()
|
|
||||||
.read_val::<RawInode>(offset)
|
|
||||||
.unwrap()
|
|
||||||
};
|
};
|
||||||
let inode_desc = Dirty::new(InodeDesc::try_from(raw_inode)?);
|
let inode_desc = Dirty::new(InodeDesc::try_from(raw_inode)?);
|
||||||
let ino = inode_idx + self.idx as u32 * fs.inodes_per_group() + 1;
|
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.
|
/// Writes back the raw inode metadata to the raw inode metadata cache.
|
||||||
pub fn sync_raw_inode(&self, inode_idx: u32, raw_inode: &RawInode) {
|
pub fn sync_raw_inode(&self, inode_idx: u32, raw_inode: &RawInode) {
|
||||||
let offset = (inode_idx as usize) * self.fs().inode_size();
|
let offset = (inode_idx as usize) * self.fs().inode_size();
|
||||||
self.raw_inodes_cache
|
self.raw_inodes_cache.write_val(offset, raw_inode).unwrap();
|
||||||
.pages()
|
|
||||||
.write_val(offset, raw_inode)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes back the metadata of this group.
|
/// Writes back the metadata of this group.
|
||||||
|
|
@ -296,8 +290,7 @@ impl BlockGroup {
|
||||||
|
|
||||||
// Writes back the raw inode metadata.
|
// Writes back the raw inode metadata.
|
||||||
self.raw_inodes_cache
|
self.raw_inodes_cache
|
||||||
.pages()
|
.flush_range(0..self.bg_impl.raw_inodes_size)?;
|
||||||
.decommit(0..self.bg_impl.raw_inodes_size)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -257,7 +257,7 @@ impl<'a> DirEntryReader<'a> {
|
||||||
let name_buf = &mut self.name_buf.as_mut().unwrap()[..name_len];
|
let name_buf = &mut self.name_buf.as_mut().unwrap()[..name_len];
|
||||||
|
|
||||||
let offset = entry_item.offset + DirEntry::HEADER_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)
|
Ok(name_buf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -265,13 +265,12 @@ impl<'a> DirEntryReader<'a> {
|
||||||
impl DirEntryIter<'_> {
|
impl DirEntryIter<'_> {
|
||||||
/// Reads a `DirEntryItem` at the current offset.
|
/// Reads a `DirEntryItem` at the current offset.
|
||||||
fn read_next_dir_entry(&mut self) -> Option<DirEntryItem> {
|
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;
|
return None;
|
||||||
};
|
};
|
||||||
|
|
||||||
let header = self
|
let header = self
|
||||||
.page_cache
|
.page_cache
|
||||||
.pages()
|
|
||||||
.read_val::<DirEntryHeader>(self.offset)
|
.read_val::<DirEntryHeader>(self.offset)
|
||||||
.ok()?;
|
.ok()?;
|
||||||
|
|
||||||
|
|
@ -391,9 +390,8 @@ impl<'a> DirEntryWriter<'a> {
|
||||||
|
|
||||||
/// Writes a `DirEntry` at the current offset. The name is written after the header.
|
/// 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<()> {
|
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
|
self.page_cache
|
||||||
.pages()
|
|
||||||
.write_bytes(self.offset + DirEntry::HEADER_LEN, name.as_bytes())?;
|
.write_bytes(self.offset + DirEntry::HEADER_LEN, name.as_bytes())?;
|
||||||
|
|
||||||
self.offset += header.record_len as usize;
|
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.
|
/// Writes the header of a `DirEntry` at the current offset.
|
||||||
pub fn write_header_only(&mut self, header: &DirEntryHeader) -> Result<()> {
|
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;
|
self.offset += header.record_len as usize;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initializes two special `DirEntry`s ("." and "..") with the given inode numbers.
|
/// Initializes two special `DirEntry`s ("." and "..") with the given inode numbers.
|
||||||
pub fn init_dir(&mut self, self_ino: u32, parent_ino: u32) -> Result<()> {
|
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);
|
let self_header = DirEntryHeader::new(self_ino, InodeType::Dir, 1);
|
||||||
self.write_entry(&self_header, ".")?;
|
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<()> {
|
fn append_entry_in_the_end(&mut self, mut header: DirEntryHeader, name: &str) -> Result<()> {
|
||||||
// Resize and append it at the new block.
|
// 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;
|
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 _;
|
header.record_len = BLOCK_SIZE as _;
|
||||||
|
|
||||||
self.offset = old_size;
|
self.offset = old_size;
|
||||||
|
|
@ -513,7 +512,7 @@ impl<'a> DirEntryWriter<'a> {
|
||||||
if is_last_entry {
|
if is_last_entry {
|
||||||
// Shrink the size.
|
// Shrink the size.
|
||||||
let new_size = pre_offset.align_up(BLOCK_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);
|
pre_entry_item.set_record_len(new_size - pre_offset);
|
||||||
self.offset = pre_offset;
|
self.offset = pre_offset;
|
||||||
self.write_header_only(&pre_entry_item.header)?;
|
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 name_buf = &mut self.name_buf.as_mut().unwrap()[..name_len];
|
||||||
|
|
||||||
let offset = item.offset + DirEntry::HEADER_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)
|
Ok(name_buf)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,8 +23,8 @@ use crate::{
|
||||||
path::{is_dot, is_dot_or_dotdot, is_dotdot},
|
path::{is_dot, is_dot_or_dotdot, is_dotdot},
|
||||||
pipe::Pipe,
|
pipe::Pipe,
|
||||||
utils::{
|
utils::{
|
||||||
Extension, FallocMode, Inode as _, InodeMode, Metadata, Permission, XattrName,
|
Extension, FallocMode, Inode as _, InodeMode, LockedCachePage, Metadata, Permission,
|
||||||
XattrNamespace, XattrSetFlags,
|
XattrName, XattrNamespace, XattrSetFlags,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
process::{Gid, Uid, posix_thread::AsPosixThread},
|
process::{Gid, Uid, posix_thread::AsPosixThread},
|
||||||
|
|
@ -99,7 +99,7 @@ impl Inode {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn page_cache(&self) -> Arc<Vmo> {
|
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 {
|
pub fn metadata(&self) -> Metadata {
|
||||||
|
|
@ -976,7 +976,7 @@ impl InodeInner {
|
||||||
let num_page_bytes = desc.num_page_bytes();
|
let num_page_bytes = desc.num_page_bytes();
|
||||||
let inode_impl = InodeImpl::new(desc, weak_self, fs);
|
let inode_impl = InodeImpl::new(desc, weak_self, fs);
|
||||||
Self {
|
Self {
|
||||||
page_cache: PageCache::with_capacity(
|
page_cache: PageCacheOps::with_capacity(
|
||||||
num_page_bytes,
|
num_page_bytes,
|
||||||
Arc::downgrade(&inode_impl.block_manager) as _,
|
Arc::downgrade(&inode_impl.block_manager) as _,
|
||||||
)
|
)
|
||||||
|
|
@ -986,7 +986,8 @@ impl InodeInner {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resize(&mut self, new_size: usize) -> Result<()> {
|
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)?;
|
self.inode_impl.resize(new_size)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -999,7 +1000,7 @@ impl InodeInner {
|
||||||
(start, end - start)
|
(start, end - start)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.page_cache.pages().read(offset, writer)?;
|
self.page_cache.read(offset, writer)?;
|
||||||
Ok(read_len)
|
Ok(read_len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1016,7 +1017,7 @@ impl InodeInner {
|
||||||
if read_len == 0 {
|
if read_len == 0 {
|
||||||
return Ok(read_len);
|
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 start_bid = Bid::from_offset(offset).to_raw() as Ext2Bid;
|
||||||
let buf_nblocks = read_len / BLOCK_SIZE;
|
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> {
|
pub fn write_at(&self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||||
let write_len = reader.remain();
|
let write_len = reader.remain();
|
||||||
self.page_cache.pages().write(offset, reader)?;
|
self.page_cache.write(offset, reader)?;
|
||||||
Ok(write_len)
|
Ok(write_len)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extend_write_at(&mut self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
pub fn extend_write_at(&mut self, offset: usize, reader: &mut VmReader) -> Result<usize> {
|
||||||
let write_len = reader.remain();
|
let write_len = reader.remain();
|
||||||
let new_size = offset + write_len;
|
let new_size = offset + write_len;
|
||||||
self.page_cache.resize(new_size.align_up(BLOCK_SIZE))?;
|
self.page_cache
|
||||||
self.page_cache.pages().write(offset, reader)?;
|
.resize(new_size.align_up(BLOCK_SIZE), self.inode_impl.file_size())?;
|
||||||
|
self.page_cache.write(offset, reader)?;
|
||||||
self.inode_impl.resize(new_size)?;
|
self.inode_impl.resize(new_size)?;
|
||||||
Ok(write_len)
|
Ok(write_len)
|
||||||
}
|
}
|
||||||
|
|
@ -1049,7 +1051,7 @@ impl InodeInner {
|
||||||
|
|
||||||
let start = offset.min(file_size);
|
let start = offset.min(file_size);
|
||||||
let end = end_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 {
|
if end_offset > file_size {
|
||||||
self.inode_impl.resize(end_offset)?;
|
self.inode_impl.resize(end_offset)?;
|
||||||
|
|
@ -1068,12 +1070,14 @@ impl InodeInner {
|
||||||
return self.inode_impl.write_fast_link(target);
|
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();
|
let file_size = self.inode_impl.file_size();
|
||||||
if file_size != target.len() {
|
if file_size != target.len() {
|
||||||
|
self.page_cache.resize(target.len(), file_size)?;
|
||||||
self.inode_impl.resize(target.len())?;
|
self.inode_impl.resize(target.len())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.page_cache.write_bytes(0, target.as_bytes())?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1084,9 +1088,7 @@ impl InodeInner {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut symlink = vec![0u8; file_size];
|
let mut symlink = vec![0u8; file_size];
|
||||||
self.page_cache
|
self.page_cache.read_bytes(0, symlink.as_mut_slice())?;
|
||||||
.pages()
|
|
||||||
.read_bytes(0, symlink.as_mut_slice())?;
|
|
||||||
|
|
||||||
Ok(String::from_utf8(symlink)?)
|
Ok(String::from_utf8(symlink)?)
|
||||||
}
|
}
|
||||||
|
|
@ -1125,7 +1127,7 @@ impl InodeInner {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let file_size = self.file_size();
|
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 {
|
if page_cache_size > file_size {
|
||||||
self.inode_impl.resize(page_cache_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<()> {
|
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 removed_entry = DirEntryWriter::new(&self.page_cache, offset).remove_entry(name)?;
|
||||||
let file_size = self.file_size();
|
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 {
|
if page_cache_size < file_size {
|
||||||
self.inode_impl.resize(page_cache_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<()> {
|
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)?;
|
DirEntryWriter::new(&self.page_cache, offset).rename_entry(old_name, new_name)?;
|
||||||
let file_size = self.file_size();
|
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 {
|
if page_cache_size != file_size {
|
||||||
self.inode_impl.resize(page_cache_size)?;
|
self.inode_impl.resize(page_cache_size)?;
|
||||||
}
|
}
|
||||||
|
|
@ -1172,7 +1174,7 @@ impl InodeInner {
|
||||||
pub fn sync_data(&self) -> Result<()> {
|
pub fn sync_data(&self) -> Result<()> {
|
||||||
// Writes back the data in page cache.
|
// Writes back the data in page cache.
|
||||||
let file_size = self.file_size();
|
let file_size = self.file_size();
|
||||||
self.page_cache.evict_range(0..file_size)?;
|
self.page_cache.flush_range(0..file_size)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1828,7 +1830,7 @@ impl InodeImpl {
|
||||||
writer: &mut VmWriter,
|
writer: &mut VmWriter,
|
||||||
) -> Result<BioWaiter>;
|
) -> Result<BioWaiter>;
|
||||||
pub fn read_blocks(&self, bid: Ext2Bid, nblocks: usize, 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<BioWaiter>;
|
pub fn read_block_async(&self, bid: Ext2Bid, frame: LockedCachePage) -> Result<BioWaiter>;
|
||||||
pub fn write_blocks_async(
|
pub fn write_blocks_async(
|
||||||
&self,
|
&self,
|
||||||
bid: Ext2Bid,
|
bid: Ext2Bid,
|
||||||
|
|
@ -1836,7 +1838,7 @@ impl InodeImpl {
|
||||||
reader: &mut VmReader,
|
reader: &mut VmReader,
|
||||||
) -> Result<BioWaiter>;
|
) -> Result<BioWaiter>;
|
||||||
pub fn write_blocks(&self, bid: Ext2Bid, nblocks: usize, 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<BioWaiter>;
|
pub fn write_block_async(&self, bid: Ext2Bid, frame: LockedCachePage) -> Result<BioWaiter>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Manages the inode blocks and block I/O operations.
|
/// Manages the inode blocks and block I/O operations.
|
||||||
|
|
@ -1965,12 +1967,12 @@ impl InodeBlockManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PageCacheBackend for 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;
|
let bid = idx as Ext2Bid;
|
||||||
self.read_block_async(bid, frame)
|
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;
|
let bid = idx as Ext2Bid;
|
||||||
self.write_block_async(bid, frame)
|
self.write_block_async(bid, frame)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ pub(super) use ostd::{
|
||||||
pub(super) use super::utils::{Dirty, IsPowerOf};
|
pub(super) use super::utils::{Dirty, IsPowerOf};
|
||||||
pub(super) use crate::{
|
pub(super) use crate::{
|
||||||
fs::utils::{
|
fs::utils::{
|
||||||
CStr256, CachePage, DirentVisitor, InodeType, PageCache, PageCacheBackend, Str16, Str64,
|
CStr256, DirentVisitor, InodeType, PageCache, PageCacheBackend, PageCacheOps, Str16, Str64,
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
time::UnixTime,
|
time::UnixTime,
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,10 @@ use core::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use align_ext::AlignExt;
|
use align_ext::AlignExt;
|
||||||
use aster_block::bio::BioWaiter;
|
|
||||||
use aster_util::slot_vec::SlotVec;
|
use aster_util::slot_vec::SlotVec;
|
||||||
use device_id::DeviceId;
|
use device_id::DeviceId;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use ostd::{
|
use ostd::sync::{PreemptDisabled, RwLockWriteGuard};
|
||||||
mm::{HasSize, io_util::HasVmReaderWriter},
|
|
||||||
sync::{PreemptDisabled, RwLockWriteGuard},
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::{memfd::MemfdInode, xattr::RamXattr, *};
|
use super::{memfd::MemfdInode, xattr::RamXattr, *};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -25,16 +21,16 @@ use crate::{
|
||||||
pipe::Pipe,
|
pipe::Pipe,
|
||||||
registry::{FsProperties, FsType},
|
registry::{FsProperties, FsType},
|
||||||
utils::{
|
utils::{
|
||||||
AccessMode, CStr256, CachePage, DirentVisitor, Extension, FallocMode, FileSystem,
|
AccessMode, CStr256, DirentVisitor, Extension, FallocMode, FileSystem,
|
||||||
FsEventSubscriberStats, FsFlags, Inode, InodeIo, InodeMode, InodeType, Metadata,
|
FsEventSubscriberStats, FsFlags, Inode, InodeIo, InodeMode, InodeType, Metadata,
|
||||||
MknodType, PageCache, PageCacheBackend, Permission, StatusFlags, SuperBlock,
|
MknodType, PageCache, PageCacheOps, Permission, StatusFlags, SuperBlock, SymbolicLink,
|
||||||
SymbolicLink, XattrName, XattrNamespace, XattrSetFlags, mkmod,
|
XattrName, XattrNamespace, XattrSetFlags, mkmod,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::{Gid, Uid},
|
process::{Gid, Uid},
|
||||||
time::clocks::RealTimeCoarseClock,
|
time::clocks::RealTimeCoarseClock,
|
||||||
vm::vmo::Vmo,
|
vm::vmo::{Vmo, VmoFlags, VmoOptions},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A volatile file system whose data and metadata exists only in memory.
|
/// 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)))
|
Self::Dir(RwLock::new(DirEntry::new(this, parent)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(self) fn new_file(this: Weak<RamInode>) -> Self {
|
pub(self) fn new_file() -> Self {
|
||||||
Self::File(PageCache::new(this).unwrap())
|
Self::File(
|
||||||
|
VmoOptions::new(0)
|
||||||
|
.flags(VmoFlags::RESIZABLE)
|
||||||
|
.alloc()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(self) fn new_symlink() -> Self {
|
pub(self) fn new_symlink() -> Self {
|
||||||
|
|
@ -160,8 +161,13 @@ impl Inner {
|
||||||
Self::NamedPipe(Pipe::new())
|
Self::NamedPipe(Pipe::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(self) fn new_file_in_memfd(this: Weak<MemfdInode>) -> Self {
|
pub(self) fn new_file_in_memfd() -> Self {
|
||||||
Self::File(PageCache::new(this).unwrap())
|
Self::File(
|
||||||
|
VmoOptions::new(0)
|
||||||
|
.flags(VmoFlags::RESIZABLE)
|
||||||
|
.alloc()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_direntry(&self) -> Option<&RwLock<DirEntry>> {
|
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> {
|
fn new_file(fs: &Arc<RamFs>, mode: InodeMode, uid: Uid, gid: Gid) -> Arc<Self> {
|
||||||
Arc::new_cyclic(|weak_self| RamInode {
|
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)),
|
metadata: SpinLock::new(InodeMeta::new(mode, uid, gid)),
|
||||||
ino: fs.alloc_id(),
|
ino: fs.alloc_id(),
|
||||||
typ: InodeType::File,
|
typ: InodeType::File,
|
||||||
|
|
@ -475,7 +481,7 @@ impl RamInode {
|
||||||
gid: Gid,
|
gid: Gid,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
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)),
|
metadata: SpinLock::new(InodeMeta::new(mode, uid, gid)),
|
||||||
ino: weak_self.as_ptr() as u64,
|
ino: weak_self.as_ptr() as u64,
|
||||||
typ: InodeType::File,
|
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 {
|
impl InodeIo for RamInode {
|
||||||
fn read_at(
|
fn read_at(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -598,7 +587,7 @@ impl InodeIo for RamInode {
|
||||||
let end = file_size.min(offset + writer.avail());
|
let end = file_size.min(offset + writer.avail());
|
||||||
(start, end - start)
|
(start, end - start)
|
||||||
};
|
};
|
||||||
page_cache.pages().read(offset, writer)?;
|
page_cache.read(offset, writer)?;
|
||||||
read_len
|
read_len
|
||||||
}
|
}
|
||||||
_ => return_errno_with_message!(Errno::EISDIR, "read is not supported"),
|
_ => 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 should_expand_size = new_size > file_size;
|
||||||
let new_size_aligned = new_size.align_up(BLOCK_SIZE);
|
let new_size_aligned = new_size.align_up(BLOCK_SIZE);
|
||||||
if should_expand_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 now = now();
|
||||||
let mut inode_meta = self.metadata.lock();
|
let mut inode_meta = self.metadata.lock();
|
||||||
|
|
@ -648,9 +637,7 @@ impl InodeIo for RamInode {
|
||||||
|
|
||||||
impl Inode for RamInode {
|
impl Inode for RamInode {
|
||||||
fn page_cache(&self) -> Option<Arc<Vmo>> {
|
fn page_cache(&self) -> Option<Arc<Vmo>> {
|
||||||
self.inner
|
self.inner.as_file().cloned()
|
||||||
.as_file()
|
|
||||||
.map(|page_cache| page_cache.pages().clone())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size(&self) -> usize {
|
fn size(&self) -> usize {
|
||||||
|
|
@ -671,7 +658,7 @@ impl Inode for RamInode {
|
||||||
}
|
}
|
||||||
|
|
||||||
let page_cache = self.inner.as_file().unwrap();
|
let page_cache = self.inner.as_file().unwrap();
|
||||||
page_cache.resize(new_size)?;
|
page_cache.resize(new_size, file_size)?;
|
||||||
|
|
||||||
let now = now();
|
let now = now();
|
||||||
let mut inode_meta = self.metadata.lock();
|
let mut inode_meta = self.metadata.lock();
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ use alloc::format;
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
|
|
||||||
use align_ext::AlignExt;
|
use align_ext::AlignExt;
|
||||||
use aster_block::bio::BioWaiter;
|
|
||||||
use aster_rights::Rights;
|
use aster_rights::Rights;
|
||||||
use inherit_methods_macro::inherit_methods;
|
use inherit_methods_macro::inherit_methods;
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
|
|
@ -18,9 +17,8 @@ use crate::{
|
||||||
path::{Mount, Path},
|
path::{Mount, Path},
|
||||||
tmpfs::TmpFs,
|
tmpfs::TmpFs,
|
||||||
utils::{
|
utils::{
|
||||||
AccessMode, CachePage, Extension, FallocMode, FileSystem, Inode, InodeIo, InodeMode,
|
AccessMode, Extension, FallocMode, FileSystem, Inode, InodeIo, InodeMode, InodeType,
|
||||||
InodeType, Metadata, PageCacheBackend, StatusFlags, XattrName, XattrNamespace,
|
Metadata, StatusFlags, XattrName, XattrNamespace, XattrSetFlags, mkmod,
|
||||||
XattrSetFlags, mkmod,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
prelude::*,
|
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")]
|
#[inherit_methods(from = "self.inode")]
|
||||||
impl InodeIo for MemfdInode {
|
impl InodeIo for MemfdInode {
|
||||||
fn read_at(
|
fn read_at(
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,11 @@ pub use inode_ext::InodeExt;
|
||||||
pub use inode_mode::InodeMode;
|
pub use inode_mode::InodeMode;
|
||||||
pub(crate) use inode_mode::{chmod, mkmod, perms_to_mask, who_and_perms_to_mask, who_to_mask};
|
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 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)]
|
#[cfg(ktest)]
|
||||||
pub use random_test::{generate_random_operation, new_fs_in_memory};
|
pub use random_test::{generate_random_operation, new_fs_in_memory};
|
||||||
pub use range_lock::{FileRange, OFFSET_MAX, RangeLockItem, RangeLockList, RangeLockType};
|
pub use range_lock::{FileRange, OFFSET_MAX, RangeLockItem, RangeLockList, RangeLockType};
|
||||||
|
|
|
||||||
|
|
@ -262,7 +262,7 @@ impl Vdso {
|
||||||
Self {
|
Self {
|
||||||
data: SpinLock::new(vdso_data),
|
data: SpinLock::new(vdso_data),
|
||||||
vmo: vdso_vmo,
|
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::{
|
use crate::{
|
||||||
fs::{
|
fs::{
|
||||||
path::{Path, PathResolver},
|
path::{Path, PathResolver},
|
||||||
utils::Inode,
|
utils::{CachePage, Inode},
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::LockedHeap,
|
process::LockedHeap,
|
||||||
thread::exception::PageFaultInfo,
|
thread::exception::PageFaultInfo,
|
||||||
vm::{
|
vm::{
|
||||||
perms::VmPerms,
|
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)
|
let (frame, is_readonly) = match self.prepare_page(page_aligned_addr, is_write)
|
||||||
{
|
{
|
||||||
Ok((frame, is_readonly)) => (frame, is_readonly),
|
Ok((frame, is_readonly)) => (frame, is_readonly),
|
||||||
Err(VmoCommitError::Err(e)) => return Err(e),
|
Err(
|
||||||
Err(VmoCommitError::NeedIo(index)) => {
|
VmoCommitError::NeedIo(index) | VmoCommitError::WaitUntilInit(index, _),
|
||||||
|
) => {
|
||||||
drop(cursor);
|
drop(cursor);
|
||||||
drop(preempt_guard);
|
drop(preempt_guard);
|
||||||
self.vmo().unwrap().commit_on(index, CommitFlags::empty())?;
|
self.vmo().unwrap().commit_on(index)?;
|
||||||
continue 'retry;
|
continue 'retry;
|
||||||
}
|
}
|
||||||
|
Err(VmoCommitError::Err(e)) => return Err(e),
|
||||||
|
Err(_) => {
|
||||||
|
unreachable!("unexpected VmoCommitError");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let vm_perms = {
|
let vm_perms = {
|
||||||
|
|
@ -549,38 +554,42 @@ impl VmMapping {
|
||||||
let mut cursor = vm_space.cursor_mut(&preempt_guard, &(start_addr..end_addr))?;
|
let mut cursor = vm_space.cursor_mut(&preempt_guard, &(start_addr..end_addr))?;
|
||||||
|
|
||||||
let rss_delta_ref = &mut rss_delta;
|
let rss_delta_ref = &mut rss_delta;
|
||||||
let operate =
|
let operate = move |commit_fn: &mut dyn FnMut() -> core::result::Result<
|
||||||
move |commit_fn: &mut dyn FnMut()
|
(usize, CachePage),
|
||||||
-> core::result::Result<UFrame, VmoCommitError>| {
|
VmoCommitError,
|
||||||
if let (_, None) = cursor.query().unwrap() {
|
>| {
|
||||||
// We regard all the surrounding pages as accessed, no matter
|
if let (_, None) = cursor.query().unwrap() {
|
||||||
// if it is really so. Then the hardware won't bother to update
|
// We regard all the surrounding pages as accessed, no matter
|
||||||
// the accessed bit of the page table on following accesses.
|
// if it is really so. Then the hardware won't bother to update
|
||||||
let page_flags = PageFlags::from(vm_perms) | PageFlags::ACCESSED;
|
// the accessed bit of the page table on following accesses.
|
||||||
let page_prop = PageProperty::new_user(page_flags, CachePolicy::Writeback);
|
let page_flags = PageFlags::from(vm_perms) | PageFlags::ACCESSED;
|
||||||
let frame = commit_fn()?;
|
let page_prop = PageProperty::new_user(page_flags, CachePolicy::Writeback);
|
||||||
cursor.map(frame, page_prop);
|
let (_, frame) = commit_fn()?;
|
||||||
rss_delta_ref.add(self.rss_type(), 1);
|
cursor.map(frame.into(), page_prop);
|
||||||
} else {
|
rss_delta_ref.add(self.rss_type(), 1);
|
||||||
let next_addr = cursor.virt_addr() + PAGE_SIZE;
|
} else {
|
||||||
if next_addr < end_addr {
|
let next_addr = cursor.virt_addr() + PAGE_SIZE;
|
||||||
let _ = cursor.jump(next_addr);
|
if next_addr < end_addr {
|
||||||
}
|
let _ = cursor.jump(next_addr);
|
||||||
}
|
}
|
||||||
Ok(())
|
}
|
||||||
};
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
let start_offset = start_addr - self.map_to_addr;
|
let start_offset = start_addr - self.map_to_addr;
|
||||||
let end_offset = end_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) {
|
match vmo.try_operate_on_range(&(start_offset..end_offset), operate) {
|
||||||
Ok(_) => return Ok(()),
|
Ok(_) => return Ok(()),
|
||||||
Err(VmoCommitError::NeedIo(index)) => {
|
Err(VmoCommitError::NeedIo(index) | VmoCommitError::WaitUntilInit(index, _)) => {
|
||||||
drop(preempt_guard);
|
drop(preempt_guard);
|
||||||
vmo.commit_on(index, CommitFlags::empty())?;
|
vmo.commit_on(index)?;
|
||||||
start_addr = (index * PAGE_SIZE - vmo.offset()) + self.map_to_addr;
|
start_addr = (index * PAGE_SIZE - vmo.offset()) + self.map_to_addr;
|
||||||
continue 'retry;
|
continue 'retry;
|
||||||
}
|
}
|
||||||
Err(VmoCommitError::Err(e)) => return Err(e),
|
Err(VmoCommitError::Err(e)) => return Err(e),
|
||||||
|
Err(_) => {
|
||||||
|
unreachable!("unexpected VmoCommitError");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -833,15 +842,17 @@ impl MappedVmo {
|
||||||
page_offset: usize,
|
page_offset: usize,
|
||||||
) -> core::result::Result<UFrame, VmoCommitError> {
|
) -> core::result::Result<UFrame, VmoCommitError> {
|
||||||
debug_assert!(page_offset.is_multiple_of(PAGE_SIZE));
|
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.
|
/// Commits a page at a specific page index.
|
||||||
///
|
///
|
||||||
/// This method may involve I/O operations if the VMO needs to fetch
|
/// This method may involve I/O operations if the VMO needs to fetch
|
||||||
/// a page from the underlying page cache.
|
/// a page from the underlying page cache.
|
||||||
pub fn commit_on(&self, page_idx: usize, commit_flags: CommitFlags) -> Result<UFrame> {
|
pub fn commit_on(&self, page_idx: usize) -> Result<UFrame> {
|
||||||
self.vmo.commit_on(page_idx, commit_flags)
|
self.vmo.commit_on(page_idx).map(|frame| frame.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Traverses the indices within a specified range of a VMO sequentially.
|
/// Traverses the indices within a specified range of a VMO sequentially.
|
||||||
|
|
@ -857,7 +868,7 @@ impl MappedVmo {
|
||||||
) -> core::result::Result<(), VmoCommitError>
|
) -> core::result::Result<(), VmoCommitError>
|
||||||
where
|
where
|
||||||
F: FnMut(
|
F: FnMut(
|
||||||
&mut dyn FnMut() -> core::result::Result<UFrame, VmoCommitError>,
|
&mut dyn FnMut() -> core::result::Result<(usize, CachePage), VmoCommitError>,
|
||||||
) -> core::result::Result<(), VmoCommitError>,
|
) -> core::result::Result<(), VmoCommitError>,
|
||||||
{
|
{
|
||||||
let range = self.offset + range.start..self.offset + range.end;
|
let range = self.offset + range.start..self.offset + range.end;
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,14 @@
|
||||||
use core::sync::atomic::AtomicUsize;
|
use core::sync::atomic::AtomicUsize;
|
||||||
|
|
||||||
use align_ext::AlignExt;
|
use align_ext::AlignExt;
|
||||||
use ostd::mm::{FrameAllocOptions, UFrame, USegment};
|
use ostd::mm::{FrameAllocOptions, Segment};
|
||||||
use xarray::XArray;
|
use xarray::XArray;
|
||||||
|
|
||||||
use super::{Pager, Vmo, VmoFlags, WritableMappingStatus};
|
use super::{Vmo, VmoFlags, WritableMappingStatus};
|
||||||
use crate::prelude::*;
|
use crate::{
|
||||||
|
fs::utils::{CachePage, CachePageMeta, PageCacheBackend},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
/// Options for allocating a root VMO.
|
/// Options for allocating a root VMO.
|
||||||
///
|
///
|
||||||
|
|
@ -38,7 +41,7 @@ use crate::prelude::*;
|
||||||
pub struct VmoOptions {
|
pub struct VmoOptions {
|
||||||
size: usize,
|
size: usize,
|
||||||
flags: VmoFlags,
|
flags: VmoFlags,
|
||||||
pager: Option<Arc<dyn Pager>>,
|
backend: Option<Weak<dyn PageCacheBackend>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VmoOptions {
|
impl VmoOptions {
|
||||||
|
|
@ -50,7 +53,7 @@ impl VmoOptions {
|
||||||
Self {
|
Self {
|
||||||
size,
|
size,
|
||||||
flags: VmoFlags::empty(),
|
flags: VmoFlags::empty(),
|
||||||
pager: None,
|
backend: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,8 +68,8 @@ impl VmoOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the pager of the VMO.
|
/// Sets the pager of the VMO.
|
||||||
pub fn pager(mut self, pager: Arc<dyn Pager>) -> Self {
|
pub fn backend(mut self, backend: Weak<dyn PageCacheBackend>) -> Self {
|
||||||
self.pager = Some(pager);
|
self.backend = Some(backend);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -75,19 +78,26 @@ impl VmoOptions {
|
||||||
/// Allocates the VMO according to the specified options.
|
/// Allocates the VMO according to the specified options.
|
||||||
pub fn alloc(self) -> Result<Arc<Vmo>> {
|
pub fn alloc(self) -> Result<Arc<Vmo>> {
|
||||||
let VmoOptions {
|
let VmoOptions {
|
||||||
size, flags, pager, ..
|
size,
|
||||||
|
flags,
|
||||||
|
backend,
|
||||||
|
..
|
||||||
} = self;
|
} = self;
|
||||||
let vmo = alloc_vmo(size, flags, pager)?;
|
let vmo = alloc_vmo(size, flags, backend)?;
|
||||||
Ok(Arc::new(vmo))
|
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 size = size.align_up(PAGE_SIZE);
|
||||||
let pages = committed_pages_if_continuous(flags, size)?;
|
let pages = committed_pages_if_continuous(flags, size)?;
|
||||||
let writable_mapping_status = WritableMappingStatus::default();
|
let writable_mapping_status = WritableMappingStatus::default();
|
||||||
Ok(Vmo {
|
Ok(Vmo {
|
||||||
pager,
|
backend,
|
||||||
flags,
|
flags,
|
||||||
pages,
|
pages,
|
||||||
size: AtomicUsize::new(size),
|
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 flags.contains(VmoFlags::CONTIGUOUS) {
|
||||||
// if the vmo is continuous, we need to allocate frames for the vmo
|
// if the vmo is continuous, we need to allocate frames for the vmo
|
||||||
let frames_num = size / PAGE_SIZE;
|
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 committed_pages = XArray::new();
|
||||||
let mut locked_pages = committed_pages.lock();
|
let mut locked_pages = committed_pages.lock();
|
||||||
let mut cursor = locked_pages.cursor_mut(0);
|
let mut cursor = locked_pages.cursor_mut(0);
|
||||||
|
|
@ -154,16 +165,18 @@ mod test {
|
||||||
|
|
||||||
#[ktest]
|
#[ktest]
|
||||||
fn resize() {
|
fn resize() {
|
||||||
|
use crate::fs::utils::PageCacheOps;
|
||||||
|
|
||||||
let vmo = VmoOptions::new(PAGE_SIZE)
|
let vmo = VmoOptions::new(PAGE_SIZE)
|
||||||
.flags(VmoFlags::RESIZABLE)
|
.flags(VmoFlags::RESIZABLE)
|
||||||
.alloc()
|
.alloc()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
vmo.write_val(10, &42u8).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.size(), 2 * PAGE_SIZE);
|
||||||
assert_eq!(vmo.read_val::<u8>(10).unwrap(), 42);
|
assert_eq!(vmo.read_val::<u8>(10).unwrap(), 42);
|
||||||
vmo.write_val(PAGE_SIZE + 20, &123u8).unwrap();
|
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);
|
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