This commit is contained in:
2021-09-13 15:37:15 +03:00
parent 7140af8ccf
commit 605ab4fe09
42 changed files with 2208 additions and 314 deletions
+11
View File
@@ -0,0 +1,11 @@
[package]
name = "ramfs"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
spin = "*"
vfs = { path = "../vfs" }
error = { path = "../../error" }
+146
View File
@@ -0,0 +1,146 @@
use core::mem::{size_of, MaybeUninit};
use core::ops::{Deref, DerefMut};
use error::Errno;
pub const SIZE: usize = 4096;
pub const ENTRY_COUNT: usize = SIZE / size_of::<usize>();
pub trait BlockAllocator {
fn alloc(&self) -> *mut u8;
unsafe fn free(&self, ptr: *mut u8);
}
pub struct BlockRef<'a, A: BlockAllocator + Copy> {
inner: Option<&'a mut [u8; SIZE]>,
alloc: MaybeUninit<A>,
}
impl<'a, A: BlockAllocator + Copy> BlockRef<'a, A> {
pub fn new(alloc: A) -> Result<Self, Errno> {
assert!(size_of::<A>() == 0);
let ptr = alloc.alloc();
if ptr.is_null() {
Err(Errno::OutOfMemory)
} else {
Ok(unsafe { Self::from_raw(alloc, ptr) })
}
}
pub fn new_indirect(alloc: A) -> Result<Self, Errno> {
let mut res = Self::new(alloc)?;
for it in res.as_mut_ref_array().iter_mut() {
it.write(BlockRef::null());
}
Ok(res)
}
pub fn null() -> Self {
Self {
inner: None,
alloc: MaybeUninit::uninit(),
}
}
pub unsafe fn from_raw(alloc: A, data: *mut u8) -> Self {
Self {
inner: Some(&mut *(data as *mut _)),
alloc: MaybeUninit::new(alloc),
}
}
pub fn is_null(&self) -> bool {
self.inner.is_none()
}
pub fn as_mut_ref_array(&mut self) -> &mut [MaybeUninit<BlockRef<'a, A>>; ENTRY_COUNT] {
assert_eq!(size_of::<Self>(), 8);
unsafe { &mut *(self.deref_mut() as *mut _ as *mut _) }
}
pub fn as_ref_array(&self) -> &[MaybeUninit<BlockRef<'a, A>>; ENTRY_COUNT] {
assert_eq!(size_of::<Self>(), 8);
unsafe { &*(self.deref() as *const _ as *const _) }
}
pub fn zero(&mut self) {
if let Some(inner) = self.inner.as_mut() {
inner.fill(0);
} else {
panic!("Tried to fill a NULL blockref");
}
}
}
impl<'a, A: BlockAllocator + Copy> Drop for BlockRef<'a, A> {
fn drop(&mut self) {
if let Some(inner) = self.inner.take() {
unsafe {
self.alloc.assume_init_ref().free(inner as *mut _ as *mut _);
}
}
}
}
impl<'a, A: BlockAllocator + Copy> Deref for BlockRef<'a, A> {
type Target = [u8; SIZE];
fn deref(&self) -> &Self::Target {
self.inner.as_ref().unwrap()
}
}
impl<'a, A: BlockAllocator + Copy> DerefMut for BlockRef<'a, A> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.inner.as_mut().unwrap()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::boxed::Box;
use std::sync::atomic::{AtomicUsize, Ordering};
static A_COUNTER: AtomicUsize = AtomicUsize::new(0);
#[test]
fn block_allocator() {
#[derive(Clone, Copy)]
struct A;
impl BlockAllocator for A {
fn alloc(&self) -> *mut u8 {
let b = Box::leak(Box::<[u8; SIZE]>::new_uninit());
A_COUNTER.fetch_add(1, Ordering::SeqCst);
b.as_mut_ptr() as *mut _
}
unsafe fn free(&self, ptr: *mut u8) {
A_COUNTER.fetch_sub(1, Ordering::SeqCst);
drop(Box::from_raw(ptr as *mut [u8; SIZE]));
}
}
const N: usize = 13;
{
let mut s: [MaybeUninit<BlockRef<A>>; N] = MaybeUninit::uninit_array();
assert_eq!(A_COUNTER.load(Ordering::Acquire), 0);
for i in 0..N {
let mut block = BlockRef::new(A {}).unwrap();
block.fill(1);
s[i].write(block);
}
assert_eq!(A_COUNTER.load(Ordering::Acquire), N);
for i in 0..N {
unsafe {
s[i].assume_init_drop();
}
}
assert_eq!(A_COUNTER.load(Ordering::Acquire), 0);
}
}
}
+691
View File
@@ -0,0 +1,691 @@
use crate::{block, BlockAllocator, BlockRef};
use core::cmp::{max, min};
use core::marker::PhantomData;
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,
l0: [MaybeUninit<BlockRef<'a, A>>; L0_BLOCKS],
l1: [MaybeUninit<BlockRef<'a, A>>; L1_BLOCKS],
l2: MaybeUninit<BlockRef<'a, A>>,
alloc: A,
}
impl<'a, A: BlockAllocator + Copy> Bvec<'a, A> {
pub fn new(alloc: A) -> Self {
let mut res = Self {
capacity: 0,
size: 0,
l0: MaybeUninit::uninit_array(),
l1: MaybeUninit::uninit_array(),
l2: MaybeUninit::uninit(),
alloc,
};
for it in res.l0.iter_mut() {
it.write(BlockRef::null());
}
for it in res.l1.iter_mut() {
it.write(BlockRef::null());
}
res.l2.write(BlockRef::null());
res
}
pub fn resize(&mut self, cap: usize) -> Result<(), Errno> {
if cap <= self.capacity {
let mut curr = self.capacity;
while curr != cap {
curr -= 1;
let mut index = curr;
if index >= L0_BLOCKS + L1_BLOCKS * block::ENTRY_COUNT {
index -= L0_BLOCKS + L1_BLOCKS * block::ENTRY_COUNT;
let l1i = index / block::ENTRY_COUNT;
let l0i = index % block::ENTRY_COUNT;
let l2r = unsafe { self.l2.assume_init_mut() };
assert!(!l2r.is_null());
let l1r = unsafe { l2r.as_mut_ref_array()[l1i].assume_init_mut() };
assert!(!l1r.is_null());
let l0r = unsafe { l1r.as_mut_ref_array()[l0i].assume_init_mut() };
assert!(!l0r.is_null());
*l0r = BlockRef::null();
if l0i == 0 {
*l1r = BlockRef::null();
}
if index == 0 {
*l2r = BlockRef::null();
}
continue;
}
if index >= L0_BLOCKS {
index -= L0_BLOCKS;
let l1i = index / block::ENTRY_COUNT;
let l0i = index % block::ENTRY_COUNT;
let l1r = unsafe { self.l1[l1i].assume_init_mut() };
assert!(!l1r.is_null());
let l0r = unsafe { l1r.as_mut_ref_array()[l0i].assume_init_mut() };
assert!(!l0r.is_null());
*l0r = BlockRef::null();
if l0i == 0 {
*l1r = BlockRef::null();
}
continue;
}
let l0r = unsafe { self.l0[index].assume_init_mut() };
assert!(!l0r.is_null());
*l0r = BlockRef::null();
continue;
unimplemented!();
}
} else {
for mut index in self.capacity..cap {
if index < L0_BLOCKS {
let l0r = unsafe { self.l0[index].assume_init_mut() };
assert!(l0r.is_null());
*l0r = BlockRef::new(self.alloc)?;
continue;
}
index -= L0_BLOCKS;
if index < L1_BLOCKS * block::ENTRY_COUNT {
let l1i = index / block::ENTRY_COUNT;
let l0i = index % block::ENTRY_COUNT;
let l1r = unsafe { self.l1[l1i].assume_init_mut() };
if l1r.is_null() {
*l1r = BlockRef::new_indirect(self.alloc)?;
}
let l0r = unsafe { l1r.as_mut_ref_array()[l0i].assume_init_mut() };
assert!(l0r.is_null());
*l0r = BlockRef::new(self.alloc)?;
continue;
}
index -= L1_BLOCKS * block::ENTRY_COUNT;
if index < block::ENTRY_COUNT * block::ENTRY_COUNT {
let l1i = index / block::ENTRY_COUNT;
let l0i = index % block::ENTRY_COUNT;
let l2r = unsafe { self.l2.assume_init_mut() };
if l2r.is_null() {
*l2r = BlockRef::new_indirect(self.alloc)?;
}
let l1r = unsafe { l2r.as_mut_ref_array()[l1i].assume_init_mut() };
if l1r.is_null() {
*l1r = BlockRef::new_indirect(self.alloc)?;
}
let l0r = unsafe { l1r.as_mut_ref_array()[l0i].assume_init_mut() };
assert!(l0r.is_null());
*l0r = BlockRef::new(self.alloc)?;
continue;
}
unimplemented!();
}
}
self.capacity = cap;
Ok(())
}
pub fn write(&mut self, mut pos: usize, data: &[u8]) -> Result<usize, Errno> {
if pos > self.size {
return Err(Errno::InvalidArgument);
}
let mut rem = data.len();
let mut doff = 0usize;
if pos + rem > self.size {
self.size = pos + rem;
self.resize((pos + rem + block::SIZE - 1) / block::SIZE)?;
}
while rem > 0 {
let index = pos / block::SIZE;
let off = pos % block::SIZE;
let count = min(block::SIZE - off, rem);
let block = &mut self[index];
let dst = &mut block[off..off + count];
let src = &data[doff..doff + count];
dst.copy_from_slice(src);
doff += count;
pos += count;
rem -= count;
}
Ok(doff)
}
pub fn read(&self, mut pos: usize, data: &mut [u8]) -> Result<usize, Errno> {
if pos > self.size {
return Err(Errno::InvalidArgument);
}
let mut rem = min(self.size - pos, data.len());
let mut doff = 0usize;
while rem > 0 {
let index = pos / block::SIZE;
let off = pos % block::SIZE;
let count = min(block::SIZE - off, rem);
let block = &self[index];
let src = &block[off..off + count];
let dst = &mut data[doff..doff + count];
dst.copy_from_slice(src);
doff += count;
pos += count;
rem -= count;
}
Ok(doff)
}
}
impl<'a, A: BlockAllocator + Copy> Index<usize> for Bvec<'a, A> {
type Output = BlockRef<'a, A>;
fn index(&self, mut index: usize) -> &Self::Output {
if index >= self.capacity {
panic!(
"Index exceeds bvec capacity ({} >= {})",
index, self.capacity
);
}
if index < L0_BLOCKS {
return unsafe { self.l0[index].assume_init_ref() };
}
index -= L0_BLOCKS;
if index < L1_BLOCKS * block::ENTRY_COUNT {
return unsafe {
let l1 = self.l1[index / block::ENTRY_COUNT].assume_init_ref();
l1.as_ref_array()[index % block::ENTRY_COUNT].assume_init_ref()
};
}
index -= L1_BLOCKS * block::ENTRY_COUNT;
if index < block::ENTRY_COUNT * block::ENTRY_COUNT {
return unsafe {
let l2 = self.l2.assume_init_ref();
let l1 = l2.as_ref_array()[index / block::ENTRY_COUNT].assume_init_ref();
l1.as_ref_array()[index % block::ENTRY_COUNT].assume_init_ref()
};
}
unimplemented!();
}
}
impl<'a, A: BlockAllocator + Copy> IndexMut<usize> for Bvec<'a, A> {
fn index_mut(&mut self, mut index: usize) -> &mut Self::Output {
if index >= self.capacity {
panic!(
"Index exceeds bvec capacity ({} >= {})",
index, self.capacity
);
}
if index < L0_BLOCKS {
return unsafe { self.l0[index].assume_init_mut() };
}
index -= L0_BLOCKS;
if index < L1_BLOCKS * block::ENTRY_COUNT {
return unsafe {
let l1 = self.l1[index / block::ENTRY_COUNT].assume_init_mut();
l1.as_mut_ref_array()[index % block::ENTRY_COUNT].assume_init_mut()
};
}
index -= L1_BLOCKS * block::ENTRY_COUNT;
if index < block::ENTRY_COUNT * block::ENTRY_COUNT {
return unsafe {
let l2 = self.l2.assume_init_mut();
let l1 = l2.as_mut_ref_array()[index / block::ENTRY_COUNT].assume_init_mut();
l1.as_mut_ref_array()[index % block::ENTRY_COUNT].assume_init_mut()
};
}
unimplemented!();
}
}
impl<'a, A: BlockAllocator + Copy> Drop for Bvec<'a, A> {
fn drop(&mut self) {
for i in 0..min(L0_BLOCKS, self.capacity) {
unsafe {
self.l0[i].assume_init_drop();
}
}
if self.capacity > L0_BLOCKS {}
}
}
#[cfg(feature = "test_bvec")]
#[cfg(test)]
mod tests {
use super::*;
use std::boxed::Box;
use std::mem::MaybeUninit;
use std::sync::atomic::{AtomicUsize, Ordering};
static A_COUNTER: AtomicUsize = AtomicUsize::new(0);
#[derive(Clone, Copy)]
struct TestAlloc;
impl BlockAllocator for TestAlloc {
fn alloc(&self) -> *mut u8 {
let b = Box::leak(Box::<[u8; block::SIZE]>::new_uninit());
eprintln!("alloc {:p}", b);
b.as_mut_ptr() as *mut _
}
unsafe fn free(&self, ptr: *mut u8) {
eprintln!("drop {:p}", ptr);
drop(Box::from_raw(ptr as *mut [u8; block::SIZE]));
}
}
#[test]
fn bvec_allocation() {
#[derive(Clone, Copy)]
struct A;
impl BlockAllocator for A {
fn alloc(&self) -> *mut u8 {
let b = Box::leak(Box::<[u8; block::SIZE]>::new_uninit());
A_COUNTER.fetch_add(1, Ordering::SeqCst);
b.as_mut_ptr() as *mut _
}
unsafe fn free(&self, ptr: *mut u8) {
A_COUNTER.fetch_sub(1, Ordering::SeqCst);
drop(Box::from_raw(ptr as *mut [u8; block::SIZE]));
}
}
let mut bvec = Bvec::new(A {});
assert_eq!(A_COUNTER.load(Ordering::Acquire), 0);
bvec.resize(123).unwrap();
unsafe {
for i in 0..L0_BLOCKS {
assert!(!bvec.l0[i].assume_init_ref().is_null());
}
let l1r = bvec.l1[0].assume_init_ref();
assert!(!l1r.is_null());
for i in 0..123 - L0_BLOCKS {
assert!(!l1r.as_ref_array()[i].assume_init_ref().is_null());
}
}
assert_eq!(A_COUNTER.load(Ordering::Acquire), 123 + 1);
bvec.resize(123 + block::ENTRY_COUNT).unwrap();
unsafe {
for i in 0..L0_BLOCKS {
assert!(!bvec.l0[i].assume_init_ref().is_null());
}
for i in 0..(123 + block::ENTRY_COUNT) - L0_BLOCKS {
let l1i = i / block::ENTRY_COUNT;
let l0i = i % block::ENTRY_COUNT;
let l1r = bvec.l1[l1i].assume_init_ref();
assert!(!l1r.is_null());
assert!(!l1r.as_ref_array()[l0i].assume_init_ref().is_null());
}
}
assert_eq!(
A_COUNTER.load(Ordering::Acquire),
123 + block::ENTRY_COUNT + 2
);
bvec.resize(L0_BLOCKS + L1_BLOCKS * block::ENTRY_COUNT)
.unwrap();
unsafe {
for i in 0..L0_BLOCKS {
assert!(!bvec.l0[i].assume_init_ref().is_null());
}
for i in 0..L1_BLOCKS * block::ENTRY_COUNT {
let l1i = i / block::ENTRY_COUNT;
let l0i = i % block::ENTRY_COUNT;
let l1r = bvec.l1[l1i].assume_init_ref();
assert!(!l1r.is_null());
assert!(!l1r.as_ref_array()[l0i].assume_init_ref().is_null());
}
}
assert_eq!(
A_COUNTER.load(Ordering::Acquire),
L0_BLOCKS + L1_BLOCKS * block::ENTRY_COUNT + L1_BLOCKS
);
bvec.resize(L0_BLOCKS + L1_BLOCKS * block::ENTRY_COUNT + block::ENTRY_COUNT * 4)
.unwrap();
unsafe {
for i in 0..L0_BLOCKS {
assert!(!bvec.l0[i].assume_init_ref().is_null());
}
for i in 0..L1_BLOCKS * block::ENTRY_COUNT {
let l1i = i / block::ENTRY_COUNT;
let l0i = i % block::ENTRY_COUNT;
let l1r = bvec.l1[l1i].assume_init_ref();
assert!(!l1r.is_null());
assert!(!l1r.as_ref_array()[l0i].assume_init_ref().is_null());
}
let l2r = bvec.l2.assume_init_ref();
assert!(!l2r.is_null());
for i in 0..block::ENTRY_COUNT * 4 {
let l1i = i / block::ENTRY_COUNT;
let l0i = i % block::ENTRY_COUNT;
let l1r = l2r.as_ref_array()[l1i].assume_init_ref();
assert!(!l1r.is_null());
assert!(!l1r.as_ref_array()[l0i].assume_init_ref().is_null());
}
}
assert_eq!(
A_COUNTER.load(Ordering::Acquire),
L0_BLOCKS + // L0
L1_BLOCKS * block::ENTRY_COUNT + L1_BLOCKS + // L1
block::ENTRY_COUNT * 4 + 4 + 1
);
bvec.resize(L0_BLOCKS + L1_BLOCKS * block::ENTRY_COUNT + block::ENTRY_COUNT * 3 + 1)
.unwrap();
unsafe {
for i in 0..L0_BLOCKS {
assert!(!bvec.l0[i].assume_init_ref().is_null());
}
for i in 0..L1_BLOCKS * block::ENTRY_COUNT {
let l1i = i / block::ENTRY_COUNT;
let l0i = i % block::ENTRY_COUNT;
let l1r = bvec.l1[l1i].assume_init_ref();
assert!(!l1r.is_null());
assert!(!l1r.as_ref_array()[l0i].assume_init_ref().is_null());
}
let l2r = bvec.l2.assume_init_ref();
assert!(!l2r.is_null());
for i in 0..block::ENTRY_COUNT * 3 + 1 {
let l1i = i / block::ENTRY_COUNT;
let l0i = i % block::ENTRY_COUNT;
let l1r = l2r.as_ref_array()[l1i].assume_init_ref();
assert!(!l1r.is_null());
assert!(!l1r.as_ref_array()[l0i].assume_init_ref().is_null());
}
}
assert_eq!(
A_COUNTER.load(Ordering::Acquire),
L0_BLOCKS + // L0
L1_BLOCKS * block::ENTRY_COUNT + L1_BLOCKS + // L1
block::ENTRY_COUNT * 3 + 1 + 4 + 1
);
bvec.resize(L0_BLOCKS + L1_BLOCKS * block::ENTRY_COUNT + block::ENTRY_COUNT * 2 + 1)
.unwrap();
unsafe {
for i in 0..L0_BLOCKS {
assert!(!bvec.l0[i].assume_init_ref().is_null());
}
for i in 0..L1_BLOCKS * block::ENTRY_COUNT {
let l1i = i / block::ENTRY_COUNT;
let l0i = i % block::ENTRY_COUNT;
let l1r = bvec.l1[l1i].assume_init_ref();
assert!(!l1r.is_null());
assert!(!l1r.as_ref_array()[l0i].assume_init_ref().is_null());
}
let l2r = bvec.l2.assume_init_ref();
assert!(!l2r.is_null());
for i in 0..block::ENTRY_COUNT * 2 + 1 {
let l1i = i / block::ENTRY_COUNT;
let l0i = i % block::ENTRY_COUNT;
let l1r = l2r.as_ref_array()[l1i].assume_init_ref();
assert!(!l1r.is_null());
assert!(!l1r.as_ref_array()[l0i].assume_init_ref().is_null());
}
}
assert_eq!(
A_COUNTER.load(Ordering::Acquire),
L0_BLOCKS + // L0
L1_BLOCKS * block::ENTRY_COUNT + L1_BLOCKS + // L1
block::ENTRY_COUNT * 2 + 1 + 3 + 1
);
bvec.resize(L0_BLOCKS + L1_BLOCKS * block::ENTRY_COUNT + 1)
.unwrap();
unsafe {
for i in 0..L0_BLOCKS {
assert!(!bvec.l0[i].assume_init_ref().is_null());
}
for i in 0..L1_BLOCKS * block::ENTRY_COUNT {
let l1i = i / block::ENTRY_COUNT;
let l0i = i % block::ENTRY_COUNT;
let l1r = bvec.l1[l1i].assume_init_ref();
assert!(!l1r.is_null());
assert!(!l1r.as_ref_array()[l0i].assume_init_ref().is_null());
}
let l2r = bvec.l2.assume_init_ref();
assert!(!l2r.is_null());
let l1r = l2r.as_ref_array()[0].assume_init_ref();
assert!(!l1r.is_null());
assert!(!l1r.as_ref_array()[0].assume_init_ref().is_null());
}
assert_eq!(
A_COUNTER.load(Ordering::Acquire),
L0_BLOCKS + // L0
L1_BLOCKS * block::ENTRY_COUNT + L1_BLOCKS + // L1
1 + 1 + 1
);
bvec.resize(L0_BLOCKS + 3 * block::ENTRY_COUNT + 1).unwrap();
unsafe {
for i in 0..L0_BLOCKS {
assert!(!bvec.l0[i].assume_init_ref().is_null());
}
for i in 0..3 * block::ENTRY_COUNT + 1 {
let l1i = i / block::ENTRY_COUNT;
let l0i = i % block::ENTRY_COUNT;
let l1r = bvec.l1[l1i].assume_init_ref();
assert!(!l1r.is_null());
assert!(!l1r.as_ref_array()[l0i].assume_init_ref().is_null());
}
let l2r = bvec.l2.assume_init_ref();
assert!(l2r.is_null());
}
assert_eq!(
A_COUNTER.load(Ordering::Acquire),
L0_BLOCKS + // L0
3 * block::ENTRY_COUNT + 1 + 4
);
bvec.resize(L0_BLOCKS).unwrap();
unsafe {
for i in 0..L0_BLOCKS {
assert!(!bvec.l0[i].assume_init_ref().is_null());
}
assert!(bvec.l1[0].assume_init_ref().is_null());
}
assert_eq!(A_COUNTER.load(Ordering::Acquire), L0_BLOCKS);
bvec.resize(12).unwrap();
unsafe {
for i in 0..12 {
assert!(!bvec.l0[i].assume_init_ref().is_null());
}
}
assert_eq!(A_COUNTER.load(Ordering::Acquire), 12);
bvec.resize(0).unwrap();
unsafe {
for i in 0..L0_BLOCKS {
assert!(bvec.l0[i].assume_init_ref().is_null());
}
}
assert_eq!(A_COUNTER.load(Ordering::Acquire), 0);
}
#[test]
fn bvec_index_l0() {
let mut bvec = Bvec::new(TestAlloc {});
bvec.resize(L0_BLOCKS).unwrap();
for i in 0..L0_BLOCKS {
let block = &bvec[i];
assert_eq!(block as *const _, bvec.l0[i].as_ptr());
}
}
#[test]
fn bvec_index_l1() {
let mut bvec = Bvec::new(TestAlloc {});
bvec.resize(L0_BLOCKS + block::ENTRY_COUNT * 2 + 3).unwrap();
for i in 0..block::ENTRY_COUNT * 2 + 3 {
let l1i = i / block::ENTRY_COUNT;
let l0i = i % block::ENTRY_COUNT;
let block = &bvec[i + L0_BLOCKS];
let l1r = unsafe { bvec.l1[l1i].assume_init_ref() };
assert_eq!(block as *const _, l1r.as_ref_array()[l0i].as_ptr());
}
}
#[test]
fn bvec_index_l2() {
let mut bvec = Bvec::new(TestAlloc {});
bvec.resize(L0_BLOCKS + L1_BLOCKS * block::ENTRY_COUNT + 3)
.unwrap();
for i in 0..3 {
let l1i = i / block::ENTRY_COUNT;
let l0i = i % block::ENTRY_COUNT;
let block = &bvec[i + L0_BLOCKS + L1_BLOCKS * block::ENTRY_COUNT];
let l2r = unsafe { bvec.l2.assume_init_ref() };
let l1r = unsafe { l2r.as_ref_array()[l1i].assume_init_ref() };
assert_eq!(block as *const _, l1r.as_ref_array()[l0i].as_ptr());
}
}
#[test]
#[should_panic]
fn bvec_index_invalid_l0_0() {
let bvec = Bvec::new(TestAlloc {});
let _block = &bvec[0];
}
#[test]
#[should_panic]
fn bvec_index_invalid_l0_1() {
let mut bvec = Bvec::new(TestAlloc {});
bvec.resize(13).unwrap();
let _block = &bvec[15];
}
#[test]
#[should_panic]
fn bvec_index_invalid_l1_0() {
let mut bvec = Bvec::new(TestAlloc {});
bvec.resize(13).unwrap();
let _block = &bvec[L0_BLOCKS + 2];
}
#[test]
#[should_panic]
fn bvec_index_invalid_l1_1() {
let mut bvec = Bvec::new(TestAlloc {});
bvec.resize(L0_BLOCKS + block::ENTRY_COUNT * 2 + 3).unwrap();
let _block = &bvec[L0_BLOCKS + block::ENTRY_COUNT * 2 + 6];
}
#[test]
#[should_panic]
fn bvec_index_invalid_l1_2() {
let mut bvec = Bvec::new(TestAlloc {});
bvec.resize(L0_BLOCKS + block::ENTRY_COUNT * 2 + 3).unwrap();
let _block = &bvec[L0_BLOCKS + block::ENTRY_COUNT * 3 + 1];
}
#[test]
#[should_panic]
fn bvec_index_invalid_l2_0() {
let mut bvec = Bvec::new(TestAlloc {});
bvec.resize(13).unwrap();
let _block = &bvec[L0_BLOCKS + L1_BLOCKS * block::ENTRY_COUNT + 3];
}
#[test]
#[should_panic]
fn bvec_index_invalid_l2_1() {
let mut bvec = Bvec::new(TestAlloc {});
bvec.resize(L0_BLOCKS + block::ENTRY_COUNT * 3 + 13)
.unwrap();
let _block = &bvec[L0_BLOCKS + L1_BLOCKS * block::ENTRY_COUNT + 3];
}
#[test]
#[should_panic]
fn bvec_index_invalid_l2_2() {
let mut bvec = Bvec::new(TestAlloc {});
bvec.resize(L0_BLOCKS + L1_BLOCKS * block::ENTRY_COUNT + 6)
.unwrap();
let _block = &bvec[L0_BLOCKS + L1_BLOCKS * block::ENTRY_COUNT + 8];
}
#[test]
#[should_panic]
fn bvec_index_invalid_l2_3() {
let mut bvec = Bvec::new(TestAlloc {});
bvec.resize(L0_BLOCKS + L1_BLOCKS * block::ENTRY_COUNT + block::ENTRY_COUNT * 2 + 7)
.unwrap();
let _block =
&bvec[L0_BLOCKS + L1_BLOCKS * block::ENTRY_COUNT + block::ENTRY_COUNT * 2 + 13];
}
#[test]
#[should_panic]
fn bvec_index_invalid_l2_4() {
let mut bvec = Bvec::new(TestAlloc {});
bvec.resize(L0_BLOCKS + L1_BLOCKS * block::ENTRY_COUNT + block::ENTRY_COUNT * 2 + 13)
.unwrap();
let _block = &bvec[L0_BLOCKS + L1_BLOCKS * block::ENTRY_COUNT + block::ENTRY_COUNT * 3 + 2];
}
#[test]
fn bvec_write_read() {
let mut bvec = Bvec::new(TestAlloc {});
const N: usize = block::SIZE * (L0_BLOCKS + L1_BLOCKS * block::ENTRY_COUNT + 3);
let mut data = vec![0u8; N];
for i in 0..N {
data[i] = (i & 0xFF) as u8;
}
assert_eq!(bvec.write(0, &data[..]), Ok(N));
let mut buf = vec![0u8; 327];
let mut off = 0usize;
let mut rem = N;
while rem != 0 {
let count = min(rem, buf.len());
assert_eq!(bvec.read(off, &mut buf[..]), Ok(count));
for i in 0..count {
assert_eq!(buf[i], ((i + off) & 0xFF) as u8);
}
rem -= count;
off += count;
}
}
}
+53
View File
@@ -0,0 +1,53 @@
#![no_std]
#![feature(new_uninit, maybe_uninit_uninit_array, maybe_uninit_extra)]
extern crate alloc;
#[cfg(test)]
#[macro_use]
extern crate std;
use alloc::rc::Rc;
use core::cell::RefCell;
use error::Errno;
use spin::Mutex;
use vfs::{Node, NodeRef, NodeType};
mod block;
pub use block::{BlockAllocator, BlockRef};
mod bvec;
use bvec::Bvec;
pub struct Ramfs<'a> {
root: NodeRef,
allocator: &'a Mutex<dyn BlockAllocator>,
}
pub struct NodeData {
}
fn load_tar(base: *const u8, size: usize) -> Result<NodeRef, Errno> {
let root = Node::directory(b"");
// TODO
Ok(root)
}
pub fn open(
base: *const u8,
size: usize,
allocator: &Mutex<dyn BlockAllocator>,
) -> Result<Ramfs, Errno> {
let root = load_tar(base, size)?;
Ok(Ramfs { root, allocator })
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ramfs_open() {
let data = include_str!("../test/test0.tar");
//let fs = open(data.as_ptr(), data.bytes().len()).unwrap();
}
}
+2
View File
@@ -0,0 +1,2 @@
This is a file
File0
Binary file not shown.
+10
View File
@@ -0,0 +1,10 @@
[package]
name = "vfs"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
error = { path = "../../error" }
spin = "*"
+187
View File
@@ -0,0 +1,187 @@
use crate::{path_element, Node, NodeRef};
use alloc::rc::Rc;
use error::Errno;
pub struct Ioctx {
pub root: NodeRef,
pub cwd: NodeRef,
}
impl Ioctx {
fn lookup_or_load(parent: NodeRef, name: &[u8]) -> Result<NodeRef, Errno> {
let p = parent.borrow_mut();
if !p.is_directory() {
return Err(Errno::NotADirectory);
}
if let Some(node) = p.children().find(|&node| node.borrow().name() == name) {
return Ok(node.clone());
}
if let Some(ops) = p.ops.as_ref() {
todo!();
}
Err(Errno::DoesNotExist)
}
fn _find(&self, mut at: NodeRef, path: &[u8]) -> Result<NodeRef, Errno> {
let mut child_path: &[u8];
let mut element_name: &[u8];
if path.is_empty() {
return Ok(at);
}
child_path = path;
loop {
let r = path_element(child_path);
element_name = r.0;
child_path = r.1;
match element_name {
b"." => {
if child_path.is_empty() {
return Ok(at);
}
}
b".." => {
let parent = at.borrow().parent().unwrap_or(at.clone());
at = parent;
if child_path.is_empty() {
return Ok(at);
}
}
_ => break,
}
}
if element_name.is_empty() && child_path.is_empty() {
return Ok(at);
}
assert!(!element_name.is_empty());
let child = Self::lookup_or_load(at, element_name)?;
if child_path.is_empty() {
Ok(child)
} else {
self._find(child, child_path)
}
}
pub fn find(&self, at: Option<NodeRef>, mut path: &[u8]) -> Result<NodeRef, Errno> {
if path.is_empty() {
return at.ok_or(Errno::DoesNotExist);
}
let at = if path[0] == b'/' {
let index = path
.iter()
.position(|&x| x != b'/')
.unwrap_or(path.len() - 1);
path = &path[index..];
self.root.clone()
} else if let Some(node) = at {
node
} else {
self.cwd.clone()
};
self._find(at, path)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Node;
#[test]
fn ioctx_find_at() {
let r = Node::directory(b"");
let d0 = Node::directory(b"dir0");
let d1 = Node::directory(b"dir1");
let d0d0 = Node::directory(b"dir0");
let d0f0 = Node::file(b"file0");
Node::attach(r.clone(), d0.clone());
Node::attach(r.clone(), d1.clone());
Node::attach(d0.clone(), d0d0.clone());
Node::attach(d0.clone(), d0f0.clone());
let ioctx = Ioctx {
root: r.clone(),
cwd: r.clone(),
};
assert!(Rc::ptr_eq(
ioctx.find(Some(r.clone()), b"dir0").as_ref().unwrap(),
&d0
));
assert!(Rc::ptr_eq(
ioctx.find(Some(d0.clone()), b"dir0").as_ref().unwrap(),
&d0d0
));
assert!(Rc::ptr_eq(
ioctx.find(Some(r.clone()), b"dir0/dir0").as_ref().unwrap(),
&d0d0
));
assert!(Rc::ptr_eq(
ioctx.find(Some(d0.clone()), b"file0").as_ref().unwrap(),
&d0f0
));
assert!(Rc::ptr_eq(
ioctx.find(Some(r.clone()), b"dir0/file0").as_ref().unwrap(),
&d0f0
));
assert!(Rc::ptr_eq(
ioctx.find(Some(d0.clone()), b"../dir1").as_ref().unwrap(),
&d1
));
assert!(Rc::ptr_eq(
ioctx.find(Some(d0.clone()), b"./dir0").as_ref().unwrap(),
&d0d0
));
assert!(Rc::ptr_eq(
ioctx.find(Some(d0.clone()), b"././dir0/.").as_ref().unwrap(),
&d0d0
));
assert!(Rc::ptr_eq(
ioctx.find(Some(d0.clone()), b"././dir0/./").as_ref().unwrap(),
&d0d0
));
assert!(Rc::ptr_eq(
ioctx.find(Some(d0.clone()), b"././dir0/").as_ref().unwrap(),
&d0d0
));
assert!(Rc::ptr_eq(
ioctx.find(Some(d0.clone()), b"././dir0/..").as_ref().unwrap(),
&d0
));
assert!(Rc::ptr_eq(
ioctx.find(Some(d0.clone()), b"././dir0/../..").as_ref().unwrap(),
&r
));
assert!(Rc::ptr_eq(
ioctx.find(Some(d0.clone()), b"././dir0/../../../").as_ref().unwrap(),
&r
));
// TODO make these illegal
assert!(Rc::ptr_eq(
ioctx.find(Some(d0.clone()), b"././file0/..").as_ref().unwrap(),
&d0
));
assert!(Rc::ptr_eq(
ioctx.find(Some(d0.clone()), b"././file0/").as_ref().unwrap(),
&d0f0
));
assert!(Rc::ptr_eq(
ioctx.find(Some(d0.clone()), b"././file0/.").as_ref().unwrap(),
&d0f0
));
ioctx.find(Some(r.clone()), b"dir0/dir1").expect_err("");
}
}
+28
View File
@@ -0,0 +1,28 @@
#![no_std]
#[allow(unused_imports)]
#[macro_use]
extern crate alloc;
#[cfg(test)]
#[macro_use]
extern crate std;
use error::Errno;
pub mod node;
mod util;
pub use node::{Node, NodeOperations, NodeRef, NodeType};
mod ioctx;
pub use ioctx::Ioctx;
pub fn path_element(path: &[u8]) -> (&[u8], &[u8]) {
if let Some(mut index) = path.iter().position(|&x| x == b'/') {
let elem = &path[..index];
while index < path.len() && path[index] == b'/' {
index += 1;
}
(elem, &path[index..])
} else {
(path, b"")
}
}
+181
View File
@@ -0,0 +1,181 @@
use crate::util::{iter::LockedIterator, FixedStr};
use alloc::{boxed::Box, rc::Rc, vec::Vec};
use core::any::Any;
use core::cell::RefCell;
use core::ffi::c_void;
use core::fmt;
use core::ptr::null_mut;
use error::Errno;
use spin::Mutex;
pub type NodeRef = Rc<RefCell<Node>>;
pub enum NodeType {
Regular,
Directory { children: Vec<NodeRef> },
}
pub const NODE_MEMORY: u32 = 1 << 0;
pub struct NodeOperations {
lookup: Option<fn(parent: NodeRef, name: &[u8]) -> Result<NodeRef, Errno>>,
drop: Option<fn(node: &mut Node)>,
}
pub struct Node {
name: FixedStr<64>,
typ: NodeType,
flags: u32,
pub(crate) ops: Option<&'static NodeOperations>,
pub data: *mut c_void,
target: Option<NodeRef>,
parent: Option<NodeRef>,
}
impl Node {
pub fn new(name: &[u8], typ: NodeType) -> Self {
let mut r = Self {
name: FixedStr::empty(),
typ,
flags: 0,
ops: None,
data: null_mut(),
parent: None,
target: None,
};
r.name.copy_from_slice(name);
r
}
pub fn directory(name: &[u8]) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(Self::new(
name,
NodeType::Directory { children: vec![] },
)))
}
pub fn file(name: &[u8]) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(Self::new(name, NodeType::Regular)))
}
pub fn name(&self) -> &FixedStr<64> {
&self.name
}
pub fn parent(&self) -> Option<NodeRef> {
self.parent.clone()
}
pub fn is_directory(&self) -> bool {
matches!(&self.typ, NodeType::Directory { .. })
}
pub fn children(&self) -> impl Iterator<Item = &NodeRef> {
let lock = TREE_MUTEX.lock();
match &self.typ {
NodeType::Directory { children } => LockedIterator::new(children.iter(), lock),
_ => panic!("Not a directory"),
}
}
pub fn children_mut(&mut self) -> impl Iterator<Item = &mut NodeRef> {
let lock = TREE_MUTEX.lock();
match &mut self.typ {
NodeType::Directory { children } => LockedIterator::new(children.iter_mut(), lock),
_ => panic!("Not a directory"),
}
}
pub fn attach(parent: NodeRef, child: NodeRef) {
let _lock = TREE_MUTEX.lock();
assert!(child.borrow().parent.is_none());
match &mut parent.borrow_mut().typ {
NodeType::Directory { children } => children.push(child.clone()),
_ => panic!("Not a directory"),
}
child.borrow_mut().parent.replace(parent.clone());
}
pub fn detach(child: NodeRef) {
let _lock = TREE_MUTEX.lock();
assert!(child.borrow().parent.is_some());
let parent = child.borrow_mut().parent.take().unwrap();
match &mut parent.borrow_mut().typ {
NodeType::Directory { children } => {
children.remove(children.iter().position(|x| Rc::ptr_eq(x, &child)).unwrap());
}
_ => panic!("Not a directory"),
};
}
}
impl Drop for Node {
fn drop(&mut self) {
if let Some(ops) = self.ops.as_ref() {
if let Some(do_drop) = ops.drop.as_ref() {
do_drop(self);
}
}
}
}
impl fmt::Debug for Node {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Node {{ name={:?}, typ=??? }}", self.name)
}
}
static TREE_MUTEX: Mutex<()> = Mutex::new(());
#[cfg(test)]
mod tests {
use super::*;
use core::any::{type_name, TypeId};
use core::sync::atomic::{AtomicBool, Ordering};
#[test]
fn node_new() {
let r = Node::directory(b"");
let n = r.borrow();
assert_eq!(n.name, b""[..]);
assert!(matches!(n.typ, NodeType::Directory { .. }));
assert!(n.ops.is_none());
assert!(n.target.is_none());
assert!(n.parent.is_none());
let r = Node::file(b"file1");
let n = r.borrow();
assert_eq!(n.name, b"file1"[..]);
assert!(matches!(n.typ, NodeType::Regular));
assert!(n.ops.is_none());
assert!(n.target.is_none());
assert!(n.parent.is_none());
}
#[test]
fn node_attach() {
let r0 = Node::directory(b"");
let r1 = Node::directory(b"1234");
// Attach
Node::attach(r0.clone(), r1.clone());
assert!(Rc::ptr_eq(r1.borrow().parent.as_ref().unwrap(), &r0));
{
let n0 = r0.borrow();
let mut it = n0.children();
assert!(Rc::ptr_eq(&it.next().unwrap(), &r1));
assert!(it.next().is_none());
}
// Detach
Node::detach(r1.clone());
assert!(r1.borrow().parent.is_none());
assert_eq!(r0.borrow().children().count(), 0);
}
}
+22
View File
@@ -0,0 +1,22 @@
use spin::MutexGuard;
pub struct LockedIterator<'a, T: ?Sized, I: Iterator<Item = T>> {
inner: I,
#[allow(dead_code)]
lock: MutexGuard<'a, ()>,
}
impl<'a, T, I: Iterator<Item = T>> Iterator for LockedIterator<'a, T, I> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
impl<'a, T, I: Iterator<Item = T>> LockedIterator<'a, T, I> {
#[inline]
pub fn new(inner: I, lock: MutexGuard<'a, ()>) -> Self {
Self { inner, lock }
}
}
+94
View File
@@ -0,0 +1,94 @@
use alloc::boxed::Box;
use core::alloc::Layout;
use core::ffi::c_void;
use core::fmt;
pub mod iter;
#[repr(transparent)]
pub struct FixedStr<const N: usize> {
inner: [u8; N],
}
impl<const N: usize> FixedStr<N> {
pub fn new(s: &[u8]) -> Self {
let mut r = Self::empty();
r.copy_from_slice(s);
r
}
pub const fn empty() -> Self {
Self { inner: [0; N] }
}
pub fn len(&self) -> usize {
self.inner.iter().position(|&n| n == 0).unwrap_or(N)
}
pub fn copy_from_slice(&mut self, src: &[u8]) {
let src_len = src.len();
if src_len == 0 {
self.inner[0] = 0;
return;
}
if src_len >= N {
panic!("String buffer overflow");
}
let dst = &mut self.inner[..src_len];
dst.copy_from_slice(src);
self.inner[src_len] = 0;
}
}
impl<const N: usize> PartialEq<[u8]> for FixedStr<N> {
fn eq(&self, other: &[u8]) -> bool {
let self_len = self.len();
if self_len != other.len() {
return false;
}
&self.inner[..self_len] == other
}
}
impl<const N: usize> fmt::Display for FixedStr<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for byte in self.inner {
if byte == 0 {
break;
}
write!(f, "{}", byte as char)?;
}
Ok(())
}
}
impl<const N: usize> fmt::Debug for FixedStr<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn fixed_str_display() {
let s = FixedStr::<64>::new(b"test");
assert_eq!(format!("{}", s), "test");
}
#[test]
fn fixed_str_length() {
assert_eq!(FixedStr::<64>::empty().len(), 0);
assert_eq!(FixedStr::<64>::new(b"test1").len(), 5);
assert_eq!(FixedStr::<6>::new(b"test1").len(), 5);
}
#[test]
fn fixed_str_eq_slice() {
assert_eq!(FixedStr::<64>::empty(), b""[..]);
assert_eq!(FixedStr::<64>::new(b"1234"), b"1234"[..]);
}
}