diff --git a/.travis.yml b/.travis.yml index 3b2fc9c..0f33674 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,3 @@ language: rust rust: - - nightly-2018-04-01 \ No newline at end of file + - nightly \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 8c256d3..7a981fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,26 +3,15 @@ name = "simple-filesystem" version = "0.0.1" authors = ["WangRunji "] -[lib] -name = "lib" -#crate-type = ["staticlib"] - [[bin]] name = "mksfs" path = "src/bin/mksfs.rs" required-features = ["std"] -[profile.dev] -panic = 'abort' # prevent `_Unwind_Resume` link error - [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" -[target.ucore.dependencies] -bitflags = "1.0" - [features] debug_print = [] -ucore = [] std = [] \ No newline at end of file diff --git a/Xargo.toml b/Xargo.toml deleted file mode 100644 index 10e8f71..0000000 --- a/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.ucore.dependencies] -alloc = {} \ No newline at end of file diff --git a/sfs-c/Cargo.toml b/sfs-c/Cargo.toml new file mode 100644 index 0000000..8d23380 --- /dev/null +++ b/sfs-c/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "sfs-c" +version = "0.0.1" +authors = ["WangRunji "] + +[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 = ".." } diff --git a/Makefile b/sfs-c/Makefile similarity index 65% rename from Makefile rename to sfs-c/Makefile index be19a06..3b65f15 100644 --- a/Makefile +++ b/sfs-c/Makefile @@ -1,6 +1,6 @@ ucore: 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: which cargo || ( curl https://sh.rustup.rs -sSf | sh ) diff --git a/sfs-c/Xargo.toml b/sfs-c/Xargo.toml new file mode 100644 index 0000000..85b3939 --- /dev/null +++ b/sfs-c/Xargo.toml @@ -0,0 +1,2 @@ +[dependencies] +alloc = {} \ No newline at end of file diff --git a/src/c_interface.rs b/sfs-c/src/lib.rs similarity index 91% rename from src/c_interface.rs rename to sfs-c/src/lib.rs index d4ef86e..5fe193f 100644 --- a/src/c_interface.rs +++ b/sfs-c/src/lib.rs @@ -3,6 +3,18 @@ //! NOTE: Must link these sections: //! `*.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 core::cell::RefCell; use core::slice; @@ -11,7 +23,8 @@ use core::cmp::Ordering; use alloc::heap::{Alloc, AllocErr, Layout}; use core::mem::{size_of, self}; use core::ptr; -use vfs; +use simple_filesystem as sfs; +use simple_filesystem as vfs; /// Lang items for bare lib mod lang { @@ -330,56 +343,40 @@ impl IoBuf { } } -impl vfs::Device for Device { - fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Option { +impl vfs::BlockedDevice for Device { + fn block_size_log2(&self) -> u8 { if self.blocksize != 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() }; + 12 + } + + fn read_at(&mut self, block_id: usize, buf: &mut [u8]) -> bool { + assert!(buf.len() >= 4096); let mut io_buf = IoBuf { - base: block_buf.as_mut_ptr(), - offset: (begin_block * 4096) as i32, + base: buf.as_mut_ptr(), + offset: (block_id * 4096) as i32, len: 4096, resident: 4096, }; let ret = (self.io)(self, &mut io_buf, false); assert_eq!(ret, ErrorCode::Ok); assert_eq!(io_buf.resident, 0); - buf.copy_from_slice(&block_buf[begin_offset .. end_offset+1]); - Some(buf.len()) + true } - fn write_at(&mut self, offset: usize, buf: &[u8]) -> Option { - if self.blocksize != 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() }; + fn write_at(&mut self, block_id: usize, buf: &[u8]) -> bool { + assert!(buf.len() >= 4096); let mut io_buf = IoBuf { - base: block_buf.as_mut_ptr(), - offset: (begin_block * 4096) as i32, + base: buf.as_ptr() as *mut _, + offset: (block_id * 4096) as i32, len: 4096, resident: 4096, }; - block_buf[begin_offset .. end_offset+1].copy_from_slice(&buf); - let ret = (self.io)(self, &mut io_buf, true); assert_eq!(ret, ErrorCode::Ok); assert_eq!(io_buf.resident, 0); - Some(buf.len()) + true } } @@ -577,6 +574,9 @@ static FS_OPS: FsOps = { /// Allocator supported by ucore functions pub struct UcoreAllocator; +#[global_allocator] +pub static UCORE_ALLOCATOR: UcoreAllocator = UcoreAllocator; + unsafe impl<'a> Alloc for &'a UcoreAllocator { unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { // cprintf!("alloc %d\n", layout.size()); diff --git a/ucore.json b/sfs-c/ucore.json similarity index 100% rename from ucore.json rename to sfs-c/ucore.json diff --git a/src/bin/mksfs.rs b/src/bin/mksfs.rs index a959f42..98d2cc6 100644 --- a/src/bin/mksfs.rs +++ b/src/bin/mksfs.rs @@ -1,11 +1,11 @@ -extern crate lib; +extern crate simple_filesystem; use std::env; use std::fs; use std::io::{Read, Write, Result}; use std::path::Path; use std::mem::uninitialized; -use lib::*; +use simple_filesystem::*; fn main() -> Result<()> { let args: Vec<_> = env::args().collect(); diff --git a/src/blocked_device.rs b/src/blocked_device.rs new file mode 100644 index 0000000..f8802fe --- /dev/null +++ b/src/blocked_device.rs @@ -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 Device for T { + fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Option { + 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 { + 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]); + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 2a504cd..1999d19 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ #![feature(alloc)] #![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] #[cfg(any(test, feature = "std"))] @@ -8,10 +8,7 @@ extern crate std; #[macro_use] extern crate alloc; -extern crate bit_set; -#[cfg(feature = "ucore")] -#[macro_use] -extern crate bitflags; +extern crate bit_vec; #[macro_use] extern crate static_assertions; @@ -23,20 +20,17 @@ macro_rules! eprintln { } mod dirty; +mod util; +mod blocked_device; mod vfs; mod sfs; mod structs; -#[cfg(feature = "ucore")] -pub mod c_interface; #[cfg(test)] mod tests; pub use sfs::*; pub use vfs::*; - -#[cfg(feature = "ucore")] -#[global_allocator] -pub static UCORE_ALLOCATOR: c_interface::UcoreAllocator = c_interface::UcoreAllocator{}; +pub use blocked_device::BlockedDevice; #[cfg(any(test, feature = "std"))] pub mod std_impl { diff --git a/src/sfs.rs b/src/sfs.rs index dddabef..3e47564 100644 --- a/src/sfs.rs +++ b/src/sfs.rs @@ -1,12 +1,13 @@ -use bit_set::BitSet; -use alloc::{boxed::Box, Vec, BTreeMap, rc::{Rc, Weak}, String}; +use bit_vec::BitVec; +use alloc::{boxed::Box, vec::Vec, collections::BTreeMap, rc::{Rc, Weak}, string::String}; use core::cell::{RefCell, RefMut}; -use dirty::Dirty; -use super::structs::*; -use super::vfs::{self, Device}; use core::mem::{uninitialized, size_of}; use core::slice; use core::fmt::{Debug, Formatter, Error}; +use dirty::Dirty; +use structs::*; +use vfs::{self, Device}; +use util::*; trait DeviceExt: Device { fn read_block(&mut self, id: BlockId, offset: usize, buf: &mut [u8]) -> vfs::Result<()> { @@ -179,6 +180,7 @@ impl INode { let iter = BlockIter { begin: size.min(begin), end: size.min(end), + block_size_log2: BLKSIZE_LOG2, }; // 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<::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 /// @@ -363,7 +331,7 @@ pub struct SimpleFileSystem { /// on-disk superblock super_block: RefCell>, /// blocks in use are mared 0 - free_map: RefCell>, + free_map: RefCell>, /// inode list inodes: RefCell>>, /// device @@ -383,7 +351,7 @@ impl SimpleFileSystem { Some(SimpleFileSystem { 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::>::new()), device: RefCell::new(device), self_ptr: Weak::default(), @@ -401,9 +369,9 @@ impl SimpleFileSystem { info: Str32::from("simple file system"), }; let free_map = { - let mut bitset = BitSet::with_capacity(BLKBITS); + let mut bitset = BitVec::from_elem(BLKBITS, false); for i in 3..blocks { - bitset.insert(i); + bitset.set(i, true); } bitset }; @@ -449,8 +417,8 @@ impl SimpleFileSystem { /// Free a block fn free_block(&self, block_id: usize) { let mut free_map = self.free_map.borrow_mut(); - assert!(!free_map.contains(block_id)); - free_map.insert(block_id); + assert!(!free_map[block_id]); + free_map.set(block_id, true); self.super_block.borrow_mut().unused_blocks += 1; } @@ -468,7 +436,7 @@ impl SimpleFileSystem { /// Get inode by id. Load if not in memory. /// ** Must ensure it's a valid INode ** fn get_inode(&self, id: INodeId) -> Ptr { - assert!(!self.free_map.borrow().contains(id)); + assert!(!self.free_map.borrow()[id]); // Load if not in memory. if !self.inodes.borrow().contains_key(&id) { @@ -542,24 +510,24 @@ trait BitsetAlloc { fn alloc(&mut self) -> Option; } -impl BitsetAlloc for BitSet { +impl BitsetAlloc for BitVec { fn alloc(&mut self) -> Option { // 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 { - self.remove(id); + self.set(id, false); } id } } -impl AsBuf for BitSet { +impl AsBuf for BitVec { 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) } } 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) } } } @@ -575,17 +543,3 @@ impl From 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); - } -} \ No newline at end of file diff --git a/src/structs.rs b/src/structs.rs index 3bd7caf..2b07667 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -153,7 +153,9 @@ pub type INodeId = BlockId; /// magic number for sfs pub const MAGIC: u32 = 0x2f8dbe2a; /// 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 pub const NDIRECT: usize = 12; /// max length of infomation diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..507630d --- /dev/null +++ b/src/util.rs @@ -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<::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); + } +} \ No newline at end of file diff --git a/src/vfs.rs b/src/vfs.rs index fa85633..ad2b560 100644 --- a/src/vfs.rs +++ b/src/vfs.rs @@ -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::mem::size_of; use core;