feat(vfs): add cow tests for memfs

This commit is contained in:
2021-10-26 13:26:47 +03:00
parent c706428ed6
commit 8274abbda1
5 changed files with 163 additions and 54 deletions
+96 -9
View File
@@ -1,11 +1,12 @@
use crate::{block, BlockAllocator, BlockRef};
use core::cmp::{max, min};
use core::marker::PhantomData;
use core::cmp::min;
use core::mem::MaybeUninit;
use core::ops::{Index, IndexMut};
use error::Errno;
const L0_BLOCKS: usize = 32; // 128K
const L1_BLOCKS: usize = 8; // 16M
pub struct Bvec<'a, A: BlockAllocator + Copy> {
capacity: usize,
size: usize,
@@ -26,7 +27,7 @@ impl<'a, A: BlockAllocator + Copy> Bvec<'a, A> {
l2: MaybeUninit::uninit(),
alloc,
#[cfg(feature = "cow")]
cow_source: core::ptr::null_mut()
cow_source: core::ptr::null_mut(),
};
for it in res.l0.iter_mut() {
it.write(BlockRef::null());
@@ -38,6 +39,11 @@ impl<'a, A: BlockAllocator + Copy> Bvec<'a, A> {
res
}
#[cfg(feature = "cow")]
pub fn is_cow(&self) -> bool {
!self.cow_source.is_null()
}
#[cfg(feature = "cow")]
pub unsafe fn setup_cow(&mut self, src: *const u8, size: usize) {
self.cow_source = src;
@@ -50,7 +56,7 @@ impl<'a, A: BlockAllocator + Copy> Bvec<'a, A> {
#[cfg(feature = "cow")]
pub fn drop_cow(&mut self) {
assert!(!self.cow_source.is_null());
assert!(self.is_cow());
let src_slice = unsafe { core::slice::from_raw_parts(self.cow_source, self.size) };
self.cow_source = core::ptr::null_mut();
@@ -60,7 +66,7 @@ impl<'a, A: BlockAllocator + Copy> Bvec<'a, A> {
pub fn resize(&mut self, cap: usize) -> Result<(), Errno> {
#[cfg(feature = "cow")]
assert!(self.cow_source.is_null());
assert!(!self.is_cow());
if cap <= self.capacity {
let mut curr = self.capacity;
@@ -104,7 +110,6 @@ impl<'a, A: BlockAllocator + Copy> Bvec<'a, A> {
assert!(!l0r.is_null());
*l0r = BlockRef::null();
continue;
unimplemented!();
}
} else {
for mut index in self.capacity..cap {
@@ -156,7 +161,7 @@ impl<'a, A: BlockAllocator + Copy> Bvec<'a, A> {
}
#[cfg(feature = "cow")]
if !self.cow_source.is_null() {
if self.is_cow() {
self.drop_cow();
}
@@ -188,7 +193,7 @@ impl<'a, A: BlockAllocator + Copy> Bvec<'a, A> {
let mut rem = min(self.size - pos, data.len());
#[cfg(feature = "cow")]
if !self.cow_source.is_null() {
if self.is_cow() {
let cow_data = unsafe { core::slice::from_raw_parts(self.cow_source, self.size) };
data[..rem].copy_from_slice(&cow_data[pos..pos + rem]);
return Ok(rem);
@@ -280,9 +285,91 @@ impl<'a, A: BlockAllocator + Copy> Drop for Bvec<'a, A> {
}
}
#[cfg(feature = "cow")]
#[cfg(test)]
mod cow_tests {
use super::*;
use std::boxed::Box;
#[derive(Clone, Copy)]
struct TestAlloc;
unsafe impl BlockAllocator for TestAlloc {
fn alloc(&self) -> *mut u8 {
let b = Box::leak(Box::new([0; block::SIZE]));
b.as_mut_ptr() as *mut _
}
unsafe fn dealloc(&self, ptr: *mut u8) {
drop(Box::from_raw(ptr as *mut [u8; block::SIZE]));
}
}
#[test]
fn bvec_write_copy_simple() {
let mut bvec = Bvec::new(TestAlloc {});
let mut buf = [0u8; 512];
let source_data = b"This is initial data\n";
unsafe {
bvec.setup_cow(source_data.as_ptr(), source_data.len());
}
assert!(bvec.is_cow());
assert_eq!(bvec.size(), source_data.len());
assert_eq!(bvec.capacity, 0);
bvec.write(8, b"testing").unwrap();
assert!(!bvec.is_cow());
assert_eq!(bvec.size(), source_data.len());
assert_eq!(bvec.capacity, 1);
assert_eq!(bvec.read(0, &mut buf).unwrap(), source_data.len());
assert_eq!(&mut buf[..source_data.len()], b"This is testing data\n");
}
#[test]
fn bvec_write_copy_l0() {
let mut bvec = Bvec::new(TestAlloc {});
let mut source_data = [0u8; 4096 * 2 - 2];
let mut buf = [0u8; 512];
for i in 0..source_data.len() {
source_data[i] = (i & 0xFF) as u8;
}
unsafe {
bvec.setup_cow(source_data.as_ptr(), source_data.len());
}
assert!(bvec.is_cow());
assert_eq!(bvec.size(), source_data.len());
assert_eq!(bvec.capacity, 0);
bvec.write(0, b"test").unwrap();
assert!(!bvec.is_cow());
assert_eq!(bvec.size(), source_data.len());
assert_eq!(bvec.capacity, 2);
assert_eq!(bvec.read(0, &mut buf).unwrap(), 512);
assert_eq!(&buf[..4], b"test");
for i in 4..512 {
assert_eq!(buf[i], (i & 0xFF) as u8);
}
assert_eq!(bvec.read(512, &mut buf).unwrap(), 512);
for i in 0..512 {
assert_eq!(buf[i], ((i + 512) & 0xFF) as u8);
}
bvec.write(source_data.len(), b"test");
assert_eq!(bvec.size(), 4096 * 2 + 2);
assert_eq!(bvec.capacity, 3);
assert_eq!(bvec.read(4096 * 2, &mut buf).unwrap(), 2);
assert_eq!(&buf[..2], b"st");
assert_eq!(bvec.read(4096 * 2 - 2, &mut buf).unwrap(), 4);
assert_eq!(&buf[..4], b"test");
}
}
#[cfg(feature = "test_bvec")]
#[cfg(test)]
mod tests {
mod bvec_tests {
use super::*;
use std::boxed::Box;
use std::mem::MaybeUninit;
+16 -17
View File
@@ -23,7 +23,7 @@ pub use block::{BlockAllocator, BlockRef};
pub mod bvec;
use bvec::Bvec;
pub mod tar;
use tar::{Tar, TarIterator};
use tar::TarIterator;
pub struct Ramfs<A: BlockAllocator + Copy + 'static> {
root: RefCell<Option<VnodeRef>>,
@@ -37,7 +37,7 @@ pub struct FileInode<'a, A: BlockAllocator + Copy + 'static> {
pub struct DirInode;
struct SetupFileParam {
data: &'static [u8]
data: &'static [u8],
}
const FILE_SETUP_COW: u64 = 0x1001;
@@ -51,11 +51,11 @@ impl<'a, A: BlockAllocator + Copy + 'static> VnodeImpl for FileInode<'a, A> {
panic!()
}
fn open(&mut self, node: VnodeRef) -> Result<usize, Errno> {
fn open(&mut self, _node: VnodeRef) -> Result<usize, Errno> {
Ok(0)
}
fn close(&mut self, node: VnodeRef) -> Result<(), Errno> {
fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> {
Ok(())
}
@@ -75,7 +75,7 @@ impl<'a, A: BlockAllocator + Copy + 'static> VnodeImpl for FileInode<'a, A> {
Ok(self.data.size())
}
fn ioctl(&mut self, node: VnodeRef, cmd: u64, value: *mut c_void) -> Result<isize, Errno> {
fn ioctl(&mut self, _node: VnodeRef, cmd: u64, value: *mut c_void) -> Result<isize, Errno> {
match cmd {
#[cfg(feature = "cow")]
FILE_SETUP_COW => {
@@ -84,8 +84,8 @@ impl<'a, A: BlockAllocator + Copy + 'static> VnodeImpl for FileInode<'a, A> {
self.data.setup_cow(data.data.as_ptr(), data.data.len());
}
Ok(0)
},
_ => Err(Errno::InvalidArgument)
}
_ => Err(Errno::InvalidArgument),
}
}
}
@@ -99,19 +99,19 @@ impl VnodeImpl for DirInode {
Ok(())
}
fn open(&mut self, node: VnodeRef) -> Result<usize, Errno> {
fn open(&mut self, _node: VnodeRef) -> Result<usize, Errno> {
todo!()
}
fn close(&mut self, node: VnodeRef) -> Result<(), Errno> {
fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> {
todo!()
}
fn read(&mut self, node: VnodeRef, pos: usize, data: &mut [u8]) -> Result<usize, Errno> {
fn read(&mut self, _node: VnodeRef, _pos: usize, _data: &mut [u8]) -> Result<usize, Errno> {
todo!()
}
fn write(&mut self, node: VnodeRef, pos: usize, data: &[u8]) -> Result<usize, Errno> {
fn write(&mut self, _node: VnodeRef, _pos: usize, _data: &[u8]) -> Result<usize, Errno> {
todo!()
}
@@ -123,7 +123,7 @@ impl VnodeImpl for DirInode {
todo!()
}
fn ioctl(&mut self, node: VnodeRef, cmd: u64, value: *mut c_void) -> Result<isize, Errno> {
fn ioctl(&mut self, _node: VnodeRef, _cmd: u64, _value: *mut c_void) -> Result<isize, Errno> {
todo!()
}
}
@@ -134,7 +134,7 @@ impl<A: BlockAllocator + Copy + 'static> Filesystem for Ramfs<A> {
}
fn create_node(self: Rc<Self>, name: &str, kind: VnodeKind) -> Result<VnodeRef, Errno> {
let mut node = Vnode::new(name, kind, Vnode::SEEKABLE);
let node = Vnode::new(name, kind, Vnode::SEEKABLE);
let data: Box<dyn VnodeImpl> = match kind {
VnodeKind::Regular => Box::new(FileInode {
data: Bvec::new(self.alloc),
@@ -151,7 +151,7 @@ impl<A: BlockAllocator + Copy + 'static> Filesystem for Ramfs<A> {
impl<A: BlockAllocator + Copy + 'static> Ramfs<A> {
pub fn open(base: *const u8, size: usize, alloc: A) -> Result<Rc<Self>, Errno> {
let mut res = Rc::new(Self {
let res = Rc::new(Self {
root: RefCell::new(None),
alloc,
});
@@ -220,9 +220,7 @@ impl<A: BlockAllocator + Copy + 'static> Ramfs<A> {
#[cfg(feature = "cow")]
{
let mut param = SetupFileParam {
data: block.data()
};
let mut param = SetupFileParam { data: block.data() };
node.ioctl(FILE_SETUP_COW, &mut param as *mut _ as *mut _)?;
}
#[cfg(not(feature = "cow"))]
@@ -244,6 +242,7 @@ impl<A: BlockAllocator + Copy + 'static> Ramfs<A> {
mod tests {
use super::*;
use alloc::boxed::Box;
use libcommon::Read;
use vfs::Ioctx;
#[test]
+15 -1
View File
@@ -67,6 +67,7 @@ mod tests {
use super::*;
use crate::{node::VnodeData, Filesystem, Ioctx, Vnode, VnodeImpl, VnodeKind, VnodeRef};
use alloc::boxed::Box;
use core::ffi::c_void;
pub struct DummyInode;
pub struct DummyFs;
@@ -107,6 +108,19 @@ mod tests {
fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> {
Err(Errno::NotImplemented)
}
fn size(&mut self, _node: VnodeRef) -> Result<usize, Errno> {
Err(Errno::NotImplemented)
}
fn ioctl(
&mut self,
_node: VnodeRef,
_cmd: u64,
_value: *mut c_void,
) -> Result<isize, Errno> {
Err(Errno::NotImplemented)
}
}
impl Filesystem for DummyFs {
@@ -115,7 +129,7 @@ mod tests {
}
fn create_node(self: Rc<Self>, name: &str, kind: VnodeKind) -> Result<VnodeRef, Errno> {
let node = Vnode::new(name, kind);
let node = Vnode::new(name, kind, 0);
node.set_data(VnodeData {
node: Box::new(DummyInode {}),
fs: self,
+25 -11
View File
@@ -75,6 +75,7 @@ mod tests {
use super::*;
use crate::{node::VnodeData, Filesystem, Vnode, VnodeImpl, VnodeKind};
use alloc::{boxed::Box, rc::Rc};
use core::ffi::c_void;
pub struct DummyInode;
pub struct DummyFs;
@@ -107,6 +108,19 @@ mod tests {
fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> {
Err(Errno::NotImplemented)
}
fn size(&mut self, _node: VnodeRef) -> Result<usize, Errno> {
Err(Errno::NotImplemented)
}
fn ioctl(
&mut self,
_node: VnodeRef,
_cmd: u64,
_value: *mut c_void,
) -> Result<isize, Errno> {
Err(Errno::NotImplemented)
}
}
impl Filesystem for DummyFs {
@@ -115,7 +129,7 @@ mod tests {
}
fn create_node(self: Rc<Self>, name: &str, kind: VnodeKind) -> Result<VnodeRef, Errno> {
let node = Vnode::new(name, kind);
let node = Vnode::new(name, kind, 0);
node.set_data(VnodeData {
node: Box::new(DummyInode {}),
fs: self,
@@ -126,12 +140,12 @@ mod tests {
#[test]
fn test_find_existing_absolute() {
let root = Vnode::new("", VnodeKind::Directory);
let d0 = Vnode::new("dir0", VnodeKind::Directory);
let d1 = Vnode::new("dir1", VnodeKind::Directory);
let d0d0 = Vnode::new("dir0", VnodeKind::Directory);
let d0f0 = Vnode::new("file0", VnodeKind::Regular);
let d1f0 = Vnode::new("file0", VnodeKind::Regular);
let root = Vnode::new("", VnodeKind::Directory, 0);
let d0 = Vnode::new("dir0", VnodeKind::Directory, 0);
let d1 = Vnode::new("dir1", VnodeKind::Directory, 0);
let d0d0 = Vnode::new("dir0", VnodeKind::Directory, 0);
let d0f0 = Vnode::new("file0", VnodeKind::Regular, 0);
let d1f0 = Vnode::new("file0", VnodeKind::Regular, 0);
root.attach(d0.clone());
root.attach(d1.clone());
@@ -182,9 +196,9 @@ mod tests {
#[test]
fn test_find_rejects_file_dots() {
let root = Vnode::new("", VnodeKind::Directory);
let d0 = Vnode::new("dir0", VnodeKind::Directory);
let d0f0 = Vnode::new("file0", VnodeKind::Regular);
let root = Vnode::new("", VnodeKind::Directory, 0);
let d0 = Vnode::new("dir0", VnodeKind::Directory, 0);
let d0f0 = Vnode::new("file0", VnodeKind::Regular, 0);
root.attach(d0.clone());
d0.attach(d0f0.clone());
@@ -207,7 +221,7 @@ mod tests {
#[test]
fn test_mkdir() {
let fs = Rc::new(DummyFs {});
let root = Vnode::new("", VnodeKind::Directory);
let root = Vnode::new("", VnodeKind::Directory, 0);
let ioctx = Ioctx::new(root.clone());
root.set_data(VnodeData {
+11 -16
View File
@@ -291,6 +291,10 @@ mod tests {
Err(Errno::NotImplemented)
}
fn size(&mut self, _node: VnodeRef) -> Result<usize, Errno> {
Err(Errno::NotImplemented)
}
fn ioctl(
&mut self,
_node: VnodeRef,
@@ -299,15 +303,6 @@ mod tests {
) -> Result<isize, Errno> {
Err(Errno::NotImplemented)
}
fn seek(
&mut self,
_node: VnodeRef,
_pos: usize,
_whence: SeekWhence,
) -> Result<usize, Errno> {
Err(Errno::NotImplemented)
}
}
impl Filesystem for DummyFs {
@@ -316,7 +311,7 @@ mod tests {
}
fn create_node(self: Rc<Self>, name: &str, kind: VnodeKind) -> Result<VnodeRef, Errno> {
let node = Vnode::new(name, kind);
let node = Vnode::new(name, kind, 0);
node.set_data(VnodeData {
node: Box::new(DummyInode {}),
fs: self,
@@ -327,8 +322,8 @@ mod tests {
#[test]
fn test_parent() {
let root = Vnode::new("", VnodeKind::Directory);
let node = Vnode::new("dir0", VnodeKind::Directory);
let root = Vnode::new("", VnodeKind::Directory, 0);
let node = Vnode::new("dir0", VnodeKind::Directory, 0);
root.attach(node.clone());
@@ -339,7 +334,7 @@ mod tests {
#[test]
fn test_mkdir_unlink() {
let fs = Rc::new(DummyFs {});
let root = Vnode::new("", VnodeKind::Directory);
let root = Vnode::new("", VnodeKind::Directory, 0);
root.set_data(VnodeData {
node: Box::new(DummyInode {}),
@@ -364,9 +359,9 @@ mod tests {
#[test]
fn test_lookup_attach_detach() {
let root = Vnode::new("", VnodeKind::Directory);
let dir0 = Vnode::new("dir0", VnodeKind::Directory);
let dir1 = Vnode::new("dir1", VnodeKind::Directory);
let root = Vnode::new("", VnodeKind::Directory, 0);
let dir0 = Vnode::new("dir0", VnodeKind::Directory, 0);
let dir1 = Vnode::new("dir1", VnodeKind::Directory, 0);
root.attach(dir0.clone());
root.attach(dir1.clone());