|
@@ -1,6 +1,8 @@
|
|
|
use crate::io::Stream;
|
|
use crate::io::Stream;
|
|
|
use crate::kernel::constants::{EEXIST, EINVAL, EIO, EISDIR, ENOENT, ENOSYS, ENOTDIR};
|
|
use crate::kernel::constants::{EEXIST, EINVAL, EIO, EISDIR, ENOENT, ENOSYS, ENOTDIR};
|
|
|
|
|
+use crate::kernel::mem::{CachePage, PageCache, PageCacheBackend};
|
|
|
use crate::kernel::timer::Instant;
|
|
use crate::kernel::timer::Instant;
|
|
|
|
|
+use crate::kernel::vfs::inode::InodeData;
|
|
|
use crate::kernel::vfs::inode::RenameData;
|
|
use crate::kernel::vfs::inode::RenameData;
|
|
|
use crate::{
|
|
use crate::{
|
|
|
io::Buffer,
|
|
io::Buffer,
|
|
@@ -16,7 +18,9 @@ use crate::{
|
|
|
prelude::*,
|
|
prelude::*,
|
|
|
};
|
|
};
|
|
|
use alloc::sync::{Arc, Weak};
|
|
use alloc::sync::{Arc, Weak};
|
|
|
|
|
+use core::fmt::Debug;
|
|
|
use core::{ops::ControlFlow, sync::atomic::Ordering};
|
|
use core::{ops::ControlFlow, sync::atomic::Ordering};
|
|
|
|
|
+use eonix_mm::paging::PAGE_SIZE;
|
|
|
use eonix_runtime::task::Task;
|
|
use eonix_runtime::task::Task;
|
|
|
use eonix_sync::{AsProof as _, AsProofMut as _, Locked, Mutex, ProofMut};
|
|
use eonix_sync::{AsProof as _, AsProofMut as _, Locked, Mutex, ProofMut};
|
|
|
use itertools::Itertools;
|
|
use itertools::Itertools;
|
|
@@ -58,7 +62,7 @@ impl Inode for NodeInode {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
define_struct_inode! {
|
|
define_struct_inode! {
|
|
|
- struct DirectoryInode {
|
|
|
|
|
|
|
+ pub(super) struct DirectoryInode {
|
|
|
entries: Locked<Vec<(Arc<[u8]>, Ino)>, ()>,
|
|
entries: Locked<Vec<(Arc<[u8]>, Ino)>, ()>,
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -152,7 +156,7 @@ impl Inode for DirectoryInode {
|
|
|
let rwsem = Task::block_on(self.rwsem.write());
|
|
let rwsem = Task::block_on(self.rwsem.write());
|
|
|
|
|
|
|
|
let ino = vfs.assign_ino();
|
|
let ino = vfs.assign_ino();
|
|
|
- let file = FileInode::new(ino, self.vfs.clone(), mode);
|
|
|
|
|
|
|
+ let file = FileInode::new(ino, self.vfs.clone(), 0, mode);
|
|
|
|
|
|
|
|
self.link(at.get_name(), file.as_ref(), rwsem.prove_mut());
|
|
self.link(at.get_name(), file.as_ref(), rwsem.prove_mut());
|
|
|
at.save_reg(file)
|
|
at.save_reg(file)
|
|
@@ -460,40 +464,60 @@ impl Inode for SymlinkInode {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
define_struct_inode! {
|
|
define_struct_inode! {
|
|
|
- struct FileInode {
|
|
|
|
|
- filedata: Locked<Vec<u8>, ()>,
|
|
|
|
|
|
|
+ pub struct FileInode {
|
|
|
|
|
+ pages: PageCache,
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+impl Debug for FileInode {
|
|
|
|
|
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
|
|
|
+ write!(f, "FileInode({:?})", self.idata)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
impl FileInode {
|
|
impl FileInode {
|
|
|
- fn new(ino: Ino, vfs: Weak<dyn Vfs>, mode: Mode) -> Arc<Self> {
|
|
|
|
|
- Self::new_locked(ino, vfs, |inode, rwsem| unsafe {
|
|
|
|
|
- addr_of_mut_field!(inode, filedata).write(Locked::new(vec![], rwsem));
|
|
|
|
|
|
|
+ pub fn new(ino: Ino, vfs: Weak<dyn Vfs>, size: usize, mode: Mode) -> Arc<Self> {
|
|
|
|
|
+ let inode = Arc::new_cyclic(|weak_self: &Weak<FileInode>| FileInode {
|
|
|
|
|
+ idata: InodeData::new(ino, vfs),
|
|
|
|
|
+ pages: PageCache::new(weak_self.clone()),
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
- addr_of_mut_field!(&mut *inode, mode).write((S_IFREG | (mode & 0o777)).into());
|
|
|
|
|
- addr_of_mut_field!(&mut *inode, nlink).write(1.into());
|
|
|
|
|
- addr_of_mut_field!(&mut *inode, ctime).write(Spin::new(Instant::now()));
|
|
|
|
|
- addr_of_mut_field!(&mut *inode, mtime).write(Spin::new(Instant::now()));
|
|
|
|
|
- addr_of_mut_field!(&mut *inode, atime).write(Spin::new(Instant::now()));
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ inode
|
|
|
|
|
+ .mode
|
|
|
|
|
+ .store(S_IFREG | (mode & 0o777), Ordering::Relaxed);
|
|
|
|
|
+ inode.nlink.store(1, Ordering::Relaxed);
|
|
|
|
|
+ inode.size.store(size as u64, Ordering::Relaxed);
|
|
|
|
|
+ inode
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+impl PageCacheBackend for FileInode {
|
|
|
|
|
+ fn read_page(&self, _cache_page: &mut CachePage, _offset: usize) -> KResult<usize> {
|
|
|
|
|
+ Ok(PAGE_SIZE)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fn write_page(&self, _page: &CachePage, _offset: usize) -> KResult<usize> {
|
|
|
|
|
+ Ok(PAGE_SIZE)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fn size(&self) -> usize {
|
|
|
|
|
+ self.size.load(Ordering::Relaxed) as usize
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
impl Inode for FileInode {
|
|
impl Inode for FileInode {
|
|
|
- fn read(&self, buffer: &mut dyn Buffer, offset: usize) -> KResult<usize> {
|
|
|
|
|
- // TODO: We don't need that strong guarantee, find some way to avoid locks
|
|
|
|
|
- let lock = Task::block_on(self.rwsem.read());
|
|
|
|
|
|
|
+ fn page_cache(&self) -> Option<&PageCache> {
|
|
|
|
|
+ Some(&self.pages)
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- match self.filedata.access(lock.prove()).split_at_checked(offset) {
|
|
|
|
|
- Some((_, data)) => buffer.fill(data).map(|result| result.allow_partial()),
|
|
|
|
|
- None => Ok(0),
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ fn read(&self, buffer: &mut dyn Buffer, offset: usize) -> KResult<usize> {
|
|
|
|
|
+ let lock = Task::block_on(self.rwsem.write());
|
|
|
|
|
+ Task::block_on(self.pages.read(buffer, offset))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
fn write(&self, stream: &mut dyn Stream, offset: WriteOffset) -> KResult<usize> {
|
|
fn write(&self, stream: &mut dyn Stream, offset: WriteOffset) -> KResult<usize> {
|
|
|
// TODO: We don't need that strong guarantee, find some way to avoid locks
|
|
// TODO: We don't need that strong guarantee, find some way to avoid locks
|
|
|
let lock = Task::block_on(self.rwsem.write());
|
|
let lock = Task::block_on(self.rwsem.write());
|
|
|
- let filedata = self.filedata.access_mut(lock.prove_mut());
|
|
|
|
|
|
|
|
|
|
let mut store_new_end = None;
|
|
let mut store_new_end = None;
|
|
|
let offset = match offset {
|
|
let offset = match offset {
|
|
@@ -506,41 +530,25 @@ impl Inode for FileInode {
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- let mut pos = offset;
|
|
|
|
|
- loop {
|
|
|
|
|
- if pos >= filedata.len() {
|
|
|
|
|
- filedata.resize(pos + 4096, 0);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ let wrote = Task::block_on(self.pages.write(stream, offset))?;
|
|
|
|
|
+ let cursor_end = offset + wrote;
|
|
|
|
|
|
|
|
- match stream.poll_data(&mut filedata[pos..])? {
|
|
|
|
|
- Some(data) => pos += data.len(),
|
|
|
|
|
- None => break,
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- filedata.resize(pos, 0);
|
|
|
|
|
if let Some(store_end) = store_new_end {
|
|
if let Some(store_end) = store_new_end {
|
|
|
- *store_end = pos;
|
|
|
|
|
|
|
+ *store_end = cursor_end;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// SAFETY: `lock` has done the synchronization
|
|
// SAFETY: `lock` has done the synchronization
|
|
|
- self.size.store(pos as u64, Ordering::Relaxed);
|
|
|
|
|
*self.mtime.lock() = Instant::now();
|
|
*self.mtime.lock() = Instant::now();
|
|
|
|
|
+ self.size.store(cursor_end as u64, Ordering::Relaxed);
|
|
|
|
|
|
|
|
- Ok(pos - offset)
|
|
|
|
|
|
|
+ Ok(wrote)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
fn truncate(&self, length: usize) -> KResult<()> {
|
|
fn truncate(&self, length: usize) -> KResult<()> {
|
|
|
- // TODO: We don't need that strong guarantee, find some way to avoid locks
|
|
|
|
|
let lock = Task::block_on(self.rwsem.write());
|
|
let lock = Task::block_on(self.rwsem.write());
|
|
|
- let filedata = self.filedata.access_mut(lock.prove_mut());
|
|
|
|
|
-
|
|
|
|
|
- // SAFETY: `lock` has done the synchronization
|
|
|
|
|
|
|
+ Task::block_on(self.pages.resize(length))?;
|
|
|
self.size.store(length as u64, Ordering::Relaxed);
|
|
self.size.store(length as u64, Ordering::Relaxed);
|
|
|
*self.mtime.lock() = Instant::now();
|
|
*self.mtime.lock() = Instant::now();
|
|
|
-
|
|
|
|
|
- filedata.resize(length, 0);
|
|
|
|
|
-
|
|
|
|
|
Ok(())
|
|
Ok(())
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -559,7 +567,7 @@ impl Inode for FileInode {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
impl_any!(TmpFs);
|
|
impl_any!(TmpFs);
|
|
|
-struct TmpFs {
|
|
|
|
|
|
|
+pub(super) struct TmpFs {
|
|
|
next_ino: AtomicIno,
|
|
next_ino: AtomicIno,
|
|
|
readonly: bool,
|
|
readonly: bool,
|
|
|
rename_lock: Mutex<()>,
|
|
rename_lock: Mutex<()>,
|
|
@@ -580,11 +588,11 @@ impl Vfs for TmpFs {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
impl TmpFs {
|
|
impl TmpFs {
|
|
|
- fn assign_ino(&self) -> Ino {
|
|
|
|
|
|
|
+ pub(super) fn assign_ino(&self) -> Ino {
|
|
|
self.next_ino.fetch_add(1, Ordering::AcqRel)
|
|
self.next_ino.fetch_add(1, Ordering::AcqRel)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- pub fn create(readonly: bool) -> KResult<(Arc<dyn Vfs>, Arc<dyn Inode>)> {
|
|
|
|
|
|
|
+ pub fn create(readonly: bool) -> KResult<(Arc<TmpFs>, Arc<DirectoryInode>)> {
|
|
|
let tmpfs = Arc::new(Self {
|
|
let tmpfs = Arc::new(Self {
|
|
|
next_ino: AtomicIno::new(1),
|
|
next_ino: AtomicIno::new(1),
|
|
|
readonly,
|
|
readonly,
|