Merge pull request #1 from wangrunji0408/mksfs

-
master
Ben "Pig" Chu 6 years ago committed by GitHub
commit 422514df9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,3 +1,3 @@
language: rust language: rust
rust: rust:
- nightly-2018-04-01 - nightly

@ -3,26 +3,15 @@ name = "simple-filesystem"
version = "0.0.1" version = "0.0.1"
authors = ["WangRunji <wangrunji0408@163.com>"] authors = ["WangRunji <wangrunji0408@163.com>"]
[lib]
name = "lib"
#crate-type = ["staticlib"]
[[bin]] [[bin]]
name = "mksfs" name = "mksfs"
path = "src/bin/mksfs.rs" path = "src/bin/mksfs.rs"
required-features = ["std"] required-features = ["std"]
[profile.dev]
panic = 'abort' # prevent `_Unwind_Resume` link error
[dependencies] [dependencies]
bit-set = { default-features = false, version = "0.5" } # default-features contains 'std' bit-vec = { default-features = false, git = "https://github.com/AltSysrq/bit-vec.git" } # default-features contains 'std'
static_assertions = "0.2.5" static_assertions = "0.2.5"
[target.ucore.dependencies]
bitflags = "1.0"
[features] [features]
debug_print = [] debug_print = []
ucore = []
std = [] std = []

@ -1,2 +0,0 @@
[target.ucore.dependencies]
alloc = {}

@ -0,0 +1,15 @@
[package]
name = "sfs-c"
version = "0.0.1"
authors = ["WangRunji <wangrunji0408@163.com>"]
[lib]
crate-type = ["staticlib"]
[profile.dev]
panic = 'abort' # prevent `_Unwind_Resume` link error
[dependencies]
bitflags = "1.0"
static_assertions = "0.2.5"
simple-filesystem = { path = ".." }

@ -1,6 +1,6 @@
ucore: ucore:
rustup override set nightly-2018-04-01 rustup override set nightly-2018-04-01
RUST_TARGET_PATH=$(shell pwd) xargo build --target ucore --features ucore RUST_TARGET_PATH=$(shell pwd) xargo build --target ucore --release
install-rust: install-rust:
which cargo || ( curl https://sh.rustup.rs -sSf | sh ) which cargo || ( curl https://sh.rustup.rs -sSf | sh )

@ -0,0 +1,2 @@
[dependencies]
alloc = {}

@ -3,6 +3,18 @@
//! NOTE: Must link these sections: //! NOTE: Must link these sections:
//! `*.got.*` `*.data.*` `*.rodata.*` //! `*.got.*` `*.data.*` `*.rodata.*`
#![feature(allocator_api, global_allocator, lang_items)]
#![feature(alloc)]
#![no_std]
#[macro_use]
extern crate alloc;
extern crate simple_filesystem;
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate static_assertions;
use alloc::{rc::Rc, boxed::Box, BTreeMap}; use alloc::{rc::Rc, boxed::Box, BTreeMap};
use core::cell::RefCell; use core::cell::RefCell;
use core::slice; use core::slice;
@ -11,7 +23,8 @@ use core::cmp::Ordering;
use alloc::heap::{Alloc, AllocErr, Layout}; use alloc::heap::{Alloc, AllocErr, Layout};
use core::mem::{size_of, self}; use core::mem::{size_of, self};
use core::ptr; use core::ptr;
use vfs; use simple_filesystem as sfs;
use simple_filesystem as vfs;
/// Lang items for bare lib /// Lang items for bare lib
mod lang { mod lang {
@ -330,56 +343,40 @@ impl IoBuf {
} }
} }
impl vfs::Device for Device { impl vfs::BlockedDevice for Device {
fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Option<usize> { fn block_size_log2(&self) -> u8 {
if self.blocksize != 4096 { if self.blocksize != 4096 {
unimplemented!("block_size != 4096 is not supported yet"); unimplemented!("block_size != 4096 is not supported yet");
} }
let begin_block = offset / 4096; 12
let end_block = (offset + buf.len() - 1) / 4096; // inclusive }
let begin_offset = offset % 4096;
let end_offset = (offset + buf.len() - 1) % 4096;
assert_eq!(begin_block, end_block, "more than 1 block is not supported yet");
use core::mem::uninitialized; fn read_at(&mut self, block_id: usize, buf: &mut [u8]) -> bool {
let mut block_buf: [u8; 4096] = unsafe{ uninitialized() }; assert!(buf.len() >= 4096);
let mut io_buf = IoBuf { let mut io_buf = IoBuf {
base: block_buf.as_mut_ptr(), base: buf.as_mut_ptr(),
offset: (begin_block * 4096) as i32, offset: (block_id * 4096) as i32,
len: 4096, len: 4096,
resident: 4096, resident: 4096,
}; };
let ret = (self.io)(self, &mut io_buf, false); let ret = (self.io)(self, &mut io_buf, false);
assert_eq!(ret, ErrorCode::Ok); assert_eq!(ret, ErrorCode::Ok);
assert_eq!(io_buf.resident, 0); assert_eq!(io_buf.resident, 0);
buf.copy_from_slice(&block_buf[begin_offset .. end_offset+1]); true
Some(buf.len())
} }
fn write_at(&mut self, offset: usize, buf: &[u8]) -> Option<usize> { fn write_at(&mut self, block_id: usize, buf: &[u8]) -> bool {
if self.blocksize != 4096 { assert!(buf.len() >= 4096);
unimplemented!("block_size != 4096 is not supported yet");
}
let begin_block = offset / 4096;
let end_block = (offset + buf.len() - 1) / 4096; // inclusive
let begin_offset = offset % 4096;
let end_offset = (offset + buf.len() - 1) % 4096;
assert_eq!(begin_block, end_block, "more than 1 block is not supported yet");
use core::mem::uninitialized;
let mut block_buf: [u8; 4096] = unsafe{ uninitialized() };
let mut io_buf = IoBuf { let mut io_buf = IoBuf {
base: block_buf.as_mut_ptr(), base: buf.as_ptr() as *mut _,
offset: (begin_block * 4096) as i32, offset: (block_id * 4096) as i32,
len: 4096, len: 4096,
resident: 4096, resident: 4096,
}; };
block_buf[begin_offset .. end_offset+1].copy_from_slice(&buf);
let ret = (self.io)(self, &mut io_buf, true); let ret = (self.io)(self, &mut io_buf, true);
assert_eq!(ret, ErrorCode::Ok); assert_eq!(ret, ErrorCode::Ok);
assert_eq!(io_buf.resident, 0); assert_eq!(io_buf.resident, 0);
Some(buf.len()) true
} }
} }
@ -577,6 +574,9 @@ static FS_OPS: FsOps = {
/// Allocator supported by ucore functions /// Allocator supported by ucore functions
pub struct UcoreAllocator; pub struct UcoreAllocator;
#[global_allocator]
pub static UCORE_ALLOCATOR: UcoreAllocator = UcoreAllocator;
unsafe impl<'a> Alloc for &'a UcoreAllocator { unsafe impl<'a> Alloc for &'a UcoreAllocator {
unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
// cprintf!("alloc %d\n", layout.size()); // cprintf!("alloc %d\n", layout.size());

@ -1,11 +1,11 @@
extern crate lib; extern crate simple_filesystem;
use std::env; use std::env;
use std::fs; use std::fs;
use std::io::{Read, Write, Result}; use std::io::{Read, Write, Result};
use std::path::Path; use std::path::Path;
use std::mem::uninitialized; use std::mem::uninitialized;
use lib::*; use simple_filesystem::*;
fn main() -> Result<()> { fn main() -> Result<()> {
let args: Vec<_> = env::args().collect(); let args: Vec<_> = env::args().collect();

@ -0,0 +1,141 @@
use util::*;
use vfs::Device;
/// Device which can only R/W in blocks
pub trait BlockedDevice {
const BLOCK_SIZE_LOG2: u8;
fn read_at(&mut self, block_id: usize, buf: &mut [u8]) -> bool;
fn write_at(&mut self, block_id: usize, buf: &[u8]) -> bool;
}
macro_rules! try0 {
($len:expr, $res:expr) => {
if(!$res) {return Some($len);}
};
}
/// Helper functions to R/W BlockedDevice in bytes
impl<T: BlockedDevice> Device for T {
fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Option<usize> {
let iter = BlockIter {
begin: offset,
end: offset + buf.len(),
block_size_log2: Self::BLOCK_SIZE_LOG2,
};
// For each block
for mut range in iter {
let len = range.origin_begin() - offset;
let buf = &mut buf[range.origin_begin() - offset..range.origin_end() - offset];
if range.is_full() {
// Read to target buf directly
try0!(len, BlockedDevice::read_at(self, range.block, buf));
} else {
use core::mem::uninitialized;
let mut block_buf: [u8; 4096] = unsafe { uninitialized() };
assert!(Self::BLOCK_SIZE_LOG2 <= 12);
// Read to local buf first
try0!(len, BlockedDevice::read_at(self, range.block, &mut block_buf));
// Copy to target buf then
buf.copy_from_slice(&mut block_buf[range.begin..range.end]);
}
}
Some(buf.len())
}
fn write_at(&mut self, offset: usize, buf: &[u8]) -> Option<usize> {
let iter = BlockIter {
begin: offset,
end: offset + buf.len(),
block_size_log2: Self::BLOCK_SIZE_LOG2,
};
// For each block
for mut range in iter {
let len = range.origin_begin() - offset;
let buf = &buf[range.origin_begin() - offset..range.origin_end() - offset];
if range.is_full() {
// Write to target buf directly
try0!(len, BlockedDevice::write_at(self, range.block, buf));
} else {
use core::mem::uninitialized;
let mut block_buf: [u8; 4096] = unsafe { uninitialized() };
assert!(Self::BLOCK_SIZE_LOG2 <= 12);
// Read to local buf first
try0!(len, BlockedDevice::read_at(self, range.block, &mut block_buf));
// Write to local buf
block_buf[range.begin..range.end].copy_from_slice(buf);
// Write back to target buf
try0!(len, BlockedDevice::write_at(self, range.block, &block_buf));
}
}
Some(buf.len())
}
}
#[cfg(test)]
mod test {
use super::*;
impl BlockedDevice for [u8; 16] {
const BLOCK_SIZE_LOG2: u8 = 2;
fn read_at(&mut self, block_id: usize, buf: &mut [u8]) -> bool {
if block_id >= 4 {
return false;
}
let begin = block_id << 2;
buf[..4].copy_from_slice(&mut self[begin..begin + 4]);
true
}
fn write_at(&mut self, block_id: usize, buf: &[u8]) -> bool {
if block_id >= 4 {
return false;
}
let begin = block_id << 2;
self[begin..begin + 4].copy_from_slice(&buf[..4]);
true
}
}
#[test]
fn read() {
let mut buf: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
let mut res: [u8; 6] = [0; 6];
// all inside
let ret = Device::read_at(&mut buf, 3, &mut res);
assert_eq!(ret, Some(6));
assert_eq!(res, [3, 4, 5, 6, 7, 8]);
// partly inside
let ret = Device::read_at(&mut buf, 11, &mut res);
assert_eq!(ret, Some(5));
assert_eq!(res, [11, 12, 13, 14, 15, 8]);
// all outside
let ret = Device::read_at(&mut buf, 16, &mut res);
assert_eq!(ret, Some(0));
assert_eq!(res, [11, 12, 13, 14, 15, 8]);
}
#[test]
fn write() {
let mut buf: [u8; 16] = [0; 16];
let mut res: [u8; 6] = [3, 4, 5, 6, 7, 8];
// all inside
let ret = Device::write_at(&mut buf, 3, &res);
assert_eq!(ret, Some(6));
assert_eq!(buf, [0, 0, 0, 3, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0]);
// partly inside
let ret = Device::write_at(&mut buf, 11, &res);
assert_eq!(ret, Some(5));
assert_eq!(buf, [0, 0, 0, 3, 4, 5, 6, 7, 8, 0, 0, 3, 4, 5, 6, 7]);
// all outside
let ret = Device::write_at(&mut buf, 16, &res);
assert_eq!(ret, Some(0));
assert_eq!(buf, [0, 0, 0, 3, 4, 5, 6, 7, 8, 0, 0, 3, 4, 5, 6, 7]);
}
}

@ -1,6 +1,6 @@
#![feature(alloc)] #![feature(alloc)]
#![feature(const_fn)] #![feature(const_fn)]
#![cfg_attr(feature = "ucore", feature(allocator_api, global_allocator, lang_items))] #![cfg_attr(target_arch = "riscv", feature(match_default_bindings))]
#![no_std] #![no_std]
#[cfg(any(test, feature = "std"))] #[cfg(any(test, feature = "std"))]
@ -8,10 +8,7 @@
extern crate std; extern crate std;
#[macro_use] #[macro_use]
extern crate alloc; extern crate alloc;
extern crate bit_set; extern crate bit_vec;
#[cfg(feature = "ucore")]
#[macro_use]
extern crate bitflags;
#[macro_use] #[macro_use]
extern crate static_assertions; extern crate static_assertions;
@ -23,20 +20,17 @@ macro_rules! eprintln {
} }
mod dirty; mod dirty;
mod util;
mod blocked_device;
mod vfs; mod vfs;
mod sfs; mod sfs;
mod structs; mod structs;
#[cfg(feature = "ucore")]
pub mod c_interface;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
pub use sfs::*; pub use sfs::*;
pub use vfs::*; pub use vfs::*;
pub use blocked_device::BlockedDevice;
#[cfg(feature = "ucore")]
#[global_allocator]
pub static UCORE_ALLOCATOR: c_interface::UcoreAllocator = c_interface::UcoreAllocator{};
#[cfg(any(test, feature = "std"))] #[cfg(any(test, feature = "std"))]
pub mod std_impl { pub mod std_impl {

@ -1,12 +1,13 @@
use bit_set::BitSet; use bit_vec::BitVec;
use alloc::{boxed::Box, Vec, BTreeMap, rc::{Rc, Weak}, String}; use alloc::{boxed::Box, vec::Vec, collections::BTreeMap, rc::{Rc, Weak}, string::String};
use core::cell::{RefCell, RefMut}; use core::cell::{RefCell, RefMut};
use dirty::Dirty;
use super::structs::*;
use super::vfs::{self, Device};
use core::mem::{uninitialized, size_of}; use core::mem::{uninitialized, size_of};
use core::slice; use core::slice;
use core::fmt::{Debug, Formatter, Error}; use core::fmt::{Debug, Formatter, Error};
use dirty::Dirty;
use structs::*;
use vfs::{self, Device};
use util::*;
trait DeviceExt: Device { trait DeviceExt: Device {
fn read_block(&mut self, id: BlockId, offset: usize, buf: &mut [u8]) -> vfs::Result<()> { fn read_block(&mut self, id: BlockId, offset: usize, buf: &mut [u8]) -> vfs::Result<()> {
@ -179,6 +180,7 @@ impl INode {
let iter = BlockIter { let iter = BlockIter {
begin: size.min(begin), begin: size.min(begin),
end: size.min(end), end: size.min(end),
block_size_log2: BLKSIZE_LOG2,
}; };
// For each block // For each block
@ -318,40 +320,6 @@ impl Drop for INode {
} }
} }
/// Given a range and iterate sub-range for each block
struct BlockIter {
begin: usize,
end: usize,
}
#[derive(Debug, Eq, PartialEq)]
struct BlockRange {
block: BlockId,
begin: usize,
end: usize,
}
impl BlockRange {
fn len(&self) -> usize {
self.end - self.begin
}
}
impl Iterator for BlockIter {
type Item = BlockRange;
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
if self.begin >= self.end {
return None;
}
let block = self.begin / BLKSIZE;
let begin = self.begin % BLKSIZE;
let end = if block == self.end / BLKSIZE { self.end % BLKSIZE } else { BLKSIZE };
self.begin += end - begin;
Some(BlockRange { block, begin, end })
}
}
/// filesystem for sfs /// filesystem for sfs
/// ///
@ -363,7 +331,7 @@ pub struct SimpleFileSystem {
/// on-disk superblock /// on-disk superblock
super_block: RefCell<Dirty<SuperBlock>>, super_block: RefCell<Dirty<SuperBlock>>,
/// blocks in use are mared 0 /// blocks in use are mared 0
free_map: RefCell<Dirty<BitSet>>, free_map: RefCell<Dirty<BitVec>>,
/// inode list /// inode list
inodes: RefCell<BTreeMap<INodeId, Ptr<INode>>>, inodes: RefCell<BTreeMap<INodeId, Ptr<INode>>>,
/// device /// device
@ -383,7 +351,7 @@ impl SimpleFileSystem {
Some(SimpleFileSystem { Some(SimpleFileSystem {
super_block: RefCell::new(Dirty::new(super_block)), super_block: RefCell::new(Dirty::new(super_block)),
free_map: RefCell::new(Dirty::new(BitSet::from_bytes(&free_map))), free_map: RefCell::new(Dirty::new(BitVec::from_bytes(&free_map))),
inodes: RefCell::new(BTreeMap::<INodeId, Ptr<INode>>::new()), inodes: RefCell::new(BTreeMap::<INodeId, Ptr<INode>>::new()),
device: RefCell::new(device), device: RefCell::new(device),
self_ptr: Weak::default(), self_ptr: Weak::default(),
@ -401,9 +369,9 @@ impl SimpleFileSystem {
info: Str32::from("simple file system"), info: Str32::from("simple file system"),
}; };
let free_map = { let free_map = {
let mut bitset = BitSet::with_capacity(BLKBITS); let mut bitset = BitVec::from_elem(BLKBITS, false);
for i in 3..blocks { for i in 3..blocks {
bitset.insert(i); bitset.set(i, true);
} }
bitset bitset
}; };
@ -449,8 +417,8 @@ impl SimpleFileSystem {
/// Free a block /// Free a block
fn free_block(&self, block_id: usize) { fn free_block(&self, block_id: usize) {
let mut free_map = self.free_map.borrow_mut(); let mut free_map = self.free_map.borrow_mut();
assert!(!free_map.contains(block_id)); assert!(!free_map[block_id]);
free_map.insert(block_id); free_map.set(block_id, true);
self.super_block.borrow_mut().unused_blocks += 1; self.super_block.borrow_mut().unused_blocks += 1;
} }
@ -468,7 +436,7 @@ impl SimpleFileSystem {
/// Get inode by id. Load if not in memory. /// Get inode by id. Load if not in memory.
/// ** Must ensure it's a valid INode ** /// ** Must ensure it's a valid INode **
fn get_inode(&self, id: INodeId) -> Ptr<INode> { fn get_inode(&self, id: INodeId) -> Ptr<INode> {
assert!(!self.free_map.borrow().contains(id)); assert!(!self.free_map.borrow()[id]);
// Load if not in memory. // Load if not in memory.
if !self.inodes.borrow().contains_key(&id) { if !self.inodes.borrow().contains_key(&id) {
@ -542,24 +510,24 @@ trait BitsetAlloc {
fn alloc(&mut self) -> Option<usize>; fn alloc(&mut self) -> Option<usize>;
} }
impl BitsetAlloc for BitSet { impl BitsetAlloc for BitVec {
fn alloc(&mut self) -> Option<usize> { fn alloc(&mut self) -> Option<usize> {
// TODO: more efficient // TODO: more efficient
let id = (0..self.len()).find(|&i| self.contains(i)); let id = (0..self.len()).find(|&i| self[i]);
if let Some(id) = id { if let Some(id) = id {
self.remove(id); self.set(id, false);
} }
id id
} }
} }
impl AsBuf for BitSet { impl AsBuf for BitVec {
fn as_buf(&self) -> &[u8] { fn as_buf(&self) -> &[u8] {
let slice = self.get_ref().storage(); let slice = self.storage();
unsafe { slice::from_raw_parts(slice as *const _ as *const u8, slice.len() * 4) } unsafe { slice::from_raw_parts(slice as *const _ as *const u8, slice.len() * 4) }
} }
fn as_buf_mut(&mut self) -> &mut [u8] { fn as_buf_mut(&mut self) -> &mut [u8] {
let slice = self.get_ref().storage(); let slice = self.storage();
unsafe { slice::from_raw_parts_mut(slice as *const _ as *mut u8, slice.len() * 4) } unsafe { slice::from_raw_parts_mut(slice as *const _ as *mut u8, slice.len() * 4) }
} }
} }
@ -575,17 +543,3 @@ impl From<FileType> for vfs::FileType {
} }
} }
} }
#[cfg(test)]
mod test {
use super::*;
#[test]
fn block_iter() {
let mut iter = BlockIter { begin: 0x123, end: 0x2018 };
assert_eq!(iter.next(), Some(BlockRange { block: 0, begin: 0x123, end: 0x1000 }));
assert_eq!(iter.next(), Some(BlockRange { block: 1, begin: 0, end: 0x1000 }));
assert_eq!(iter.next(), Some(BlockRange { block: 2, begin: 0, end: 0x18 }));
assert_eq!(iter.next(), None);
}
}

@ -153,7 +153,9 @@ pub type INodeId = BlockId;
/// magic number for sfs /// magic number for sfs
pub const MAGIC: u32 = 0x2f8dbe2a; pub const MAGIC: u32 = 0x2f8dbe2a;
/// size of block /// size of block
pub const BLKSIZE: usize = 4096; pub const BLKSIZE: usize = 1usize << BLKSIZE_LOG2;
/// log2( size of block )
pub const BLKSIZE_LOG2: u8 = 12;
/// number of direct blocks in inode /// number of direct blocks in inode
pub const NDIRECT: usize = 12; pub const NDIRECT: usize = 12;
/// max length of infomation /// max length of infomation

@ -0,0 +1,60 @@
/// Given a range and iterate sub-range for each block
pub struct BlockIter {
pub begin: usize,
pub end: usize,
pub block_size_log2: u8,
}
#[derive(Debug, Eq, PartialEq)]
pub struct BlockRange {
pub block: usize,
pub begin: usize,
pub end: usize,
pub block_size_log2: u8,
}
impl BlockRange {
pub fn len(&self) -> usize {
self.end - self.begin
}
pub fn is_full(&self) -> bool {
self.len() == (1usize << self.block_size_log2)
}
pub fn origin_begin(&self) -> usize {
(self.block << self.block_size_log2) + self.begin
}
pub fn origin_end(&self) -> usize {
(self.block << self.block_size_log2) + self.end
}
}
impl Iterator for BlockIter {
type Item = BlockRange;
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
if self.begin >= self.end {
return None;
}
let block_size_log2 = self.block_size_log2;
let block_size = 1usize << self.block_size_log2;
let block = self.begin / block_size;
let begin = self.begin % block_size;
let end = if block == self.end / block_size { self.end % block_size } else { block_size };
self.begin += end - begin;
Some(BlockRange { block, begin, end, block_size_log2 })
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn block_iter() {
let mut iter = BlockIter { begin: 0x123, end: 0x2018, block_size_log2: 12 };
assert_eq!(iter.next(), Some(BlockRange { block: 0, begin: 0x123, end: 0x1000, block_size_log2: 12 }));
assert_eq!(iter.next(), Some(BlockRange { block: 1, begin: 0, end: 0x1000, block_size_log2: 12 }));
assert_eq!(iter.next(), Some(BlockRange { block: 2, begin: 0, end: 0x18, block_size_log2: 12 }));
assert_eq!(iter.next(), None);
}
}

@ -1,4 +1,4 @@
use alloc::{Vec, String, rc::{Rc, Weak}}; use alloc::{vec::Vec, string::String, rc::{Rc, Weak}};
use core::cell::RefCell; use core::cell::RefCell;
use core::mem::size_of; use core::mem::size_of;
use core; use core;

Loading…
Cancel
Save