Add Dirty wrapper. Add some functions without test.

master
WangRunji 7 years ago
parent 3a45996496
commit cbb0e341c0

@ -0,0 +1,47 @@
use core::ops::{Deref, DerefMut};
/// Dirty wraps a value of type T with functions similiar to that of a Read/Write
/// lock but simply sets a dirty flag on write(), reset on read()
pub struct Dirty<T> {
value: T,
dirty: bool,
}
impl<T> Dirty<T> {
/// Create a new Dirty
pub fn new(val: T) -> Dirty<T> {
Dirty {
value: val,
dirty: false,
}
}
/// Returns true if dirty, false otherwise
#[allow(dead_code)]
pub fn dirty(&self) -> bool {
self.dirty
}
/// Reset dirty
pub fn sync(&mut self) {
self.dirty = false;
}
}
impl<T> Deref for Dirty<T> {
type Target = T;
/// Read the value
fn deref(&self) -> &T {
&self.value
}
}
impl<T> DerefMut for Dirty<T> {
/// Writable value return, sets the dirty flag
fn deref_mut(&mut self) -> &mut T {
self.dirty = true;
&mut self.value
}
}

@ -9,6 +9,8 @@ extern crate spin;
extern crate alloc;
extern crate bit_set;
mod dirty;
mod vfs;
mod sfs;
mod structs;
#[cfg(test)]

@ -1,6 +1,7 @@
use spin::Mutex;
use bit_set::BitSet;
use alloc::{boxed::Box, Vec};
use alloc::{boxed::Box, Vec, BTreeMap, rc::Rc};
use dirty::Dirty;
use super::structs::*;
use core::mem::{uninitialized, size_of};
use core::slice;
@ -13,46 +14,32 @@ pub trait Device {
}
/// inode for sfs
pub struct Inode {
pub struct INode {
/// on-disk inode
disk_inode: *mut DiskInode,
disk_inode: Dirty<DiskINode>,
/// inode number
id: u32,
/// true if inode modified
dirty: bool,
/// kill inode if it hits zero
reclaim_count: u32,
/// semaphore for din
mutex: Mutex<()>,
id: INodeId,
}
type INodeId = usize;
/// filesystem for sfs
pub struct SimpleFileSystem {
/// on-disk superblock
super_block: SuperBlock,
super_block: Dirty<SuperBlock>,
/// blocks in use are mared 0
free_map: BitSet,
/// true if super/freemap modified
super_dirty: bool,
/// buffer for non-block aligned io
// buffer: u8,
/// semaphore for fs
// fs_mutex: Mutex<()>,
/// semaphore for link/unlink and rename
// link_mutex: Mutex<()>,
/// inode list
// inodes: Vec<Inode>,
inodes: BTreeMap<INodeId, Rc<INode>>,
/// device
device: Mutex<Box<Device>>,
device: Box<Device>,
}
impl SimpleFileSystem {
/// Create a new SFS with device
pub fn new(mut device: Box<Device>) -> Option<Self> {
let mut super_block: SuperBlock = unsafe{ uninitialized() };
let slice = unsafe{ slice::from_raw_parts_mut(
&mut super_block as *mut SuperBlock as *mut u8, size_of::<SuperBlock>()) };
if device.read_at(0, slice).is_none() {
if device.read_at(0, super_block.as_buf_mut()).is_none() {
return None;
}
if super_block.check() == false {
@ -60,10 +47,61 @@ impl SimpleFileSystem {
}
Some(SimpleFileSystem {
super_block,
super_block: Dirty::new(super_block),
free_map: BitSet::new(),
super_dirty: false,
device: Mutex::new(device),
inodes: BTreeMap::<INodeId, Rc<INode>>::new(),
device,
})
}
/// Allocate a block, return block id
fn alloc_block(&mut self) -> Option<usize> {
let id = self.free_map.alloc();
if id.is_some() {
self.super_block.unused_blocks -= 1; // will panic if underflow
}
id
}
/// Free a block
fn free_block(&mut self, block_id: usize) {
assert!(!self.free_map.contains(block_id));
self.free_map.insert(block_id);
self.super_block.unused_blocks += 1;
}
/// Get inode by id
fn get_inode(&self, id: INodeId) -> Option<Rc<INode>> {
self.inodes.get(&id).map(|rc| rc.clone())
}
/// Write back super block if dirty
fn sync(&mut self) {
let SimpleFileSystem {
ref mut super_block,
ref mut device,
..
} = self;
if super_block.dirty() {
device.write_at(0, super_block.as_buf());
super_block.sync();
}
}
}
trait BitsetAlloc {
fn alloc(&mut self) -> Option<usize>;
}
impl BitsetAlloc for BitSet {
fn alloc(&mut self) -> Option<usize> {
// TODO: more efficient
let id = (0 .. self.len()).find(|&i| self.contains(i));
if let Some(id) = id {
self.remove(id);
}
id
}
}
#[cfg(test)]
mod test {
use super::*;
}

@ -1,3 +1,6 @@
use core::slice;
use core::mem::size_of_val;
/// On-disk superblock
#[repr(C, packed)]
pub struct SuperBlock {
@ -14,7 +17,7 @@ pub struct SuperBlock {
/// inode (on disk)
#[repr(C, packed)]
#[derive(Debug)]
pub struct DiskInode {
pub struct DiskINode {
/// size of the file (in bytes)
pub size: u32,
/// one of SYS_TYPE_* above
@ -35,7 +38,7 @@ pub struct DiskInode {
#[repr(C, packed)]
pub struct DiskEntry {
/// inode number
pub inode_number: u32,
pub id: u32,
/// file name
pub name: [u8; MAX_FNAME_LEN + 1],
}
@ -46,6 +49,19 @@ impl SuperBlock {
}
}
/// Convert structs to [u8] slice
pub trait AsBuf {
fn as_buf(&self) -> &[u8] {
unsafe{ slice::from_raw_parts(self as *const _ as *const u8, size_of_val(self)) }
}
fn as_buf_mut(&mut self) -> &mut [u8] {
unsafe{ slice::from_raw_parts_mut(self as *mut _ as *mut u8, size_of_val(self)) }
}
}
impl AsBuf for SuperBlock {}
impl AsBuf for DiskINode {}
/*
* Simple FS (SFS) definitions visible to ucore. This covers the on-disk format
* and is used by tools that work on SFS volumes, such as mksfs.
@ -77,3 +93,16 @@ pub const BLK_NENTRY: usize = BLKSIZE / 4;
pub enum FileType {
Invalid = 0, File = 1, Dir = 2, Link = 3,
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn struct_size() {
use core::mem::size_of;
assert!(size_of::<SuperBlock>() <= BLKSIZE);
assert!(size_of::<DiskINode>() <= BLKSIZE);
assert!(size_of::<DiskEntry>() <= BLKSIZE);
}
}

@ -0,0 +1,17 @@
/// Abstract operations on a inode.
pub trait INodeOps {
fn open(&mut self, flags: u32) -> Result<(), ()>;
fn close(&mut self) -> Result<(), ()>;
fn read(&mut self, buf: &mut [u8]) -> Result<(), ()>;
fn write(&mut self, buf: &[u8]) -> Result<(), ()>;
// fn fstat(&mut self, buf: &[u8]) -> Result<(), ()>;
// fn fsync(&mut self) -> Result<(), ()>;
// fn name_file(&mut self) -> Result<(), ()>;
// fn reclaim(&mut self) -> Result<(), ()>;
// fn get_type(&mut self) -> Result<u32, ()>;
// fn try_seek(&mut self, offset: u64) -> Result<(), ()>;
// fn truncate(&mut self, len: u64) -> Result<(), ()>;
// fn create(&mut self, name: &'static str, excl: bool) -> Result<(), ()>;
// fn loopup(&mut self, path: &'static str) -> Result<(), ()>;
// fn io_ctrl(&mut self, op: u32, data: &[u8]) -> Result<(), ()>;
}
Loading…
Cancel
Save