Reimplement fmap/funmap using improvements to kernel

parent cb2bcf9f
Pipeline #3686 failed with stages
in 1 minute and 44 seconds
[[package]]
name = "bitflags"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cfg-if"
version = "0.1.6"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "fuchsia-zircon"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fuchsia-zircon-sys"
version = "0.3.3"
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
......@@ -27,16 +13,16 @@ name = "fuse"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"thread-scoped 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "libc"
version = "0.2.45"
version = "0.2.51"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
......@@ -52,7 +38,7 @@ name = "log"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
......@@ -62,27 +48,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rand"
version = "0.3.22"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.4.3"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "redox_syscall"
version = "0.1.49"
version = "0.1.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
......@@ -90,18 +98,12 @@ name = "redoxfs"
version = "0.3.2"
dependencies = [
"fuse 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.49 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.53 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"uuid 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "spin"
version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "thread-scoped"
version = "1.0.2"
......@@ -109,12 +111,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "time"
version = "0.1.41"
version = "0.1.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.49 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.53 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
......@@ -122,12 +124,12 @@ name = "uuid"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi"
version = "0.3.6"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
......@@ -145,22 +147,22 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum fuse 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80e57070510966bfef93662a81cb8aa2b1c7db0964354fa9921434f04b9e8660"
"checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74"
"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917"
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"
"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1"
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
"checksum redox_syscall 0.1.49 (registry+https://github.com/rust-lang/crates.io-index)" = "f22c50afdcf3f0a31ebb6b47697f6a7c5e5a24967e842858118bce0615f0afad"
"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f"
"checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c"
"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum redox_syscall 0.1.53 (registry+https://github.com/rust-lang/crates.io-index)" = "53848511b7ee6eb9d5c3db48481aaa5779b38fc0131bc133c98cb4f2b2411928"
"checksum thread-scoped 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bcbb6aa301e5d3b0b5ef639c9a9c7e2f1c944f177b460c04dc24c69b1fa2bd99"
"checksum time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "847da467bf0db05882a9e2375934a8a55cffdc9db0d128af1518200260ba1f6c"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
"checksum uuid 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcc7e3b898aa6f6c08e5295b6c89258d1331e9ac578cc992fb818759951bdc22"
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
......@@ -22,7 +22,6 @@ path = "src/bin/mkfs.rs"
doc = false
[dependencies]
spin = "0.4"
redox_syscall = "0.1"
uuid = { version = "0.5", features = ["v4"] }
......
......@@ -81,6 +81,7 @@ impl<T: Disk> Disk for DiskCache<T> {
}
fn write_at(&mut self, block: u64, buffer: &[u8]) -> Result<usize> {
//TODO: Write only blocks that have changed
// println!("Cache write at {}", block);
self.inner.write_at(block, buffer)?;
......
extern crate spin;
use syscall;
use syscall::{Packet, Scheme};
use std::fs::File;
......
use std::cmp::{min, max};
use std::collections::BTreeMap;
use std::slice;
use std::time::{SystemTime, UNIX_EPOCH};
use syscall::data::{Map, Stat, TimeSpec};
use syscall::error::{Error, Result, EBADF, EBUSY, EINVAL, EISDIR, EPERM};
use syscall::error::{Error, Result, EBADF, EINVAL, EISDIR, ENOMEM, EPERM};
use syscall::flag::{O_ACCMODE, O_RDONLY, O_WRONLY, O_RDWR, F_GETFL, F_SETFL, MODE_PERM, PROT_READ, PROT_WRITE, SEEK_SET, SEEK_CUR, SEEK_END};
use disk::Disk;
use filesystem::FileSystem;
use super::scheme::{Fmaps, FmapKey, FmapValue};
pub trait Resource<D: Disk> {
fn block(&self) -> u64;
......@@ -15,14 +16,14 @@ pub trait Resource<D: Disk> {
fn read(&mut self, buf: &mut [u8], fs: &mut FileSystem<D>) -> Result<usize>;
fn write(&mut self, buf: &[u8], fs: &mut FileSystem<D>) -> Result<usize>;
fn seek(&mut self, offset: usize, whence: usize, fs: &mut FileSystem<D>) -> Result<usize>;
fn fmap(&mut self, map: &Map, maps: &mut Fmaps, fs: &mut FileSystem<D>) -> Result<usize>;
fn funmap(&mut self, maps: &mut Fmaps, fs: &mut FileSystem<D>) -> Result<usize>;
fn fmap(&mut self, map: &Map, fs: &mut FileSystem<D>) -> Result<usize>;
fn funmap(&mut self, address: usize, fs: &mut FileSystem<D>) -> Result<usize>;
fn fchmod(&mut self, mode: u16, fs: &mut FileSystem<D>) -> Result<usize>;
fn fchown(&mut self, uid: u32, gid: u32, fs: &mut FileSystem<D>) -> Result<usize>;
fn fcntl(&mut self, cmd: usize, arg: usize) -> Result<usize>;
fn path(&self, buf: &mut [u8]) -> Result<usize>;
fn stat(&self, _stat: &mut Stat, fs: &mut FileSystem<D>) -> Result<usize>;
fn sync(&mut self, maps: &mut Fmaps, fs: &mut FileSystem<D>) -> Result<usize>;
fn sync(&mut self, fs: &mut FileSystem<D>) -> Result<usize>;
fn truncate(&mut self, len: usize, fs: &mut FileSystem<D>) -> Result<usize>;
fn utimens(&mut self, times: &[TimeSpec], fs: &mut FileSystem<D>) -> Result<usize>;
}
......@@ -89,10 +90,10 @@ impl<D: Disk> Resource<D> for DirResource {
Ok(self.seek)
}
fn fmap(&mut self, _map: &Map, _maps: &mut Fmaps, _fs: &mut FileSystem<D>) -> Result<usize> {
fn fmap(&mut self, _map: &Map, _fs: &mut FileSystem<D>) -> Result<usize> {
Err(Error::new(EBADF))
}
fn funmap(&mut self, _maps: &mut Fmaps, _fs: &mut FileSystem<D>) -> Result<usize> {
fn funmap(&mut self, _address: usize, _fs: &mut FileSystem<D>) -> Result<usize> {
Err(Error::new(EBADF))
}
......@@ -167,7 +168,7 @@ impl<D: Disk> Resource<D> for DirResource {
Ok(0)
}
fn sync(&mut self, _maps: &mut Fmaps, _fs: &mut FileSystem<D>) -> Result<usize> {
fn sync(&mut self, _fs: &mut FileSystem<D>) -> Result<usize> {
Err(Error::new(EBADF))
}
......@@ -180,13 +181,78 @@ impl<D: Disk> Resource<D> for DirResource {
}
}
pub struct Fmap {
block: u64,
offset: usize,
flags: usize,
data: &'static mut [u8],
}
impl Fmap {
pub unsafe fn new<D: Disk>(block: u64, map: &Map, fs: &mut FileSystem<D>) -> Result<Self> {
extern "C" {
fn memalign(align: usize, size: usize) -> *mut u8;
fn free(ptr: *mut u8);
}
// Memory provided to fmap must be page aligned and sized
let align = 4096;
let address = memalign(align, ((map.size + align - 1) / align) * align);
if address.is_null() {
return Err(Error::new(ENOMEM));
}
// Read buffer from disk
let buf = slice::from_raw_parts_mut(address, map.size);
let count = match fs.read_node(block, map.offset as u64, buf) {
Ok(ok) => ok,
Err(err) => {
free(address);
return Err(err);
}
};
// Make sure remaining data is zeroed
for i in count..buf.len() {
buf[i] = 0;
}
Ok(Self {
block,
offset: map.offset,
flags: map.flags,
data: &mut buf[..count],
})
}
pub fn sync<D: Disk>(&mut self, fs: &mut FileSystem<D>) -> Result<()> {
if self.flags & PROT_WRITE == PROT_WRITE {
let mtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
fs.write_node(self.block, self.offset as u64, &self.data, mtime.as_secs(), mtime.subsec_nanos())?;
}
Ok(())
}
}
impl Drop for Fmap {
fn drop(&mut self) {
unsafe {
extern "C" {
fn free(ptr: *mut u8);
}
free(self.data.as_mut_ptr());
}
}
}
pub struct FileResource {
path: String,
block: u64,
flags: usize,
seek: u64,
uid: u32,
fmap: Option<(usize, FmapKey)>
fmaps: BTreeMap<usize, Fmap>,
}
impl FileResource {
......@@ -197,35 +263,9 @@ impl FileResource {
flags: flags,
seek: seek,
uid: uid,
fmap: None
fmaps: BTreeMap::new(),
}
}
fn sync_fmap<D: Disk>(&mut self, maps: &mut Fmaps, fs: &mut FileSystem<D>) -> Result<()> {
if let Some((i, key_exact)) = self.fmap.as_ref() {
let (key_round, value) = maps.index(*i).as_mut().expect("mapping dropped while still referenced");
let rel_offset = key_exact.offset - key_round.offset;
// Minimum out of our size and the original file size
let actual_size = (value.actual_size - rel_offset).min(key_exact.size);
let mtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
let mut count = 0;
while count < actual_size {
match fs.write_node(self.block, key_exact.offset as u64 + count as u64,
&value.buffer[rel_offset..][count..actual_size],
mtime.as_secs(), mtime.subsec_nanos())? {
0 => {
eprintln!("Fmap failed to write whole buffer, encountered EOF early.");
break;
}
n => count += n,
}
}
}
Ok(())
}
}
impl<D: Disk> Resource<D> for FileResource {
......@@ -240,7 +280,7 @@ impl<D: Disk> Resource<D> for FileResource {
flags: self.flags,
seek: self.seek,
uid: self.uid,
fmap: None
fmaps: BTreeMap::new(),
}))
}
......@@ -278,7 +318,7 @@ impl<D: Disk> Resource<D> for FileResource {
Ok(self.seek as usize)
}
fn fmap(&mut self, map: &Map, maps: &mut Fmaps, fs: &mut FileSystem<D>) -> Result<usize> {
fn fmap(&mut self, map: &Map, fs: &mut FileSystem<D>) -> Result<usize> {
let accmode = self.flags & O_ACCMODE;
if map.flags & PROT_READ > 0 && ! (accmode == O_RDWR || accmode == O_RDONLY) {
return Err(Error::new(EBADF));
......@@ -288,66 +328,20 @@ impl<D: Disk> Resource<D> for FileResource {
}
//TODO: PROT_EXEC?
let key_exact = FmapKey {
block: self.block,
offset: map.offset,
size: map.size
};
let map = unsafe { Fmap::new(self.block, map, fs)? };
let address = map.data.as_ptr() as usize;
self.fmaps.insert(address, map);
Ok(address)
}
let i = match maps.find_compatible(&key_exact) {
Ok((i, (key_existing, value))) => {
value.refcount += 1;
self.fmap = Some((i, key_exact));
return Ok(value.buffer.as_ptr() as usize + (key_exact.offset - key_existing.offset))
},
Err(None) => {
// This is bad!
// We reached the limit of maps, and we can't reallocate
// because that would invalidate stuff.
// Sorry, nothing personal :(
return Err(Error::new(EBUSY))
},
Err(Some(i)) => {
// Can't do stuff in here because lifetime issues
i
}
};
let key_round = key_exact.round();
let mut content = vec![0; key_round.size];
let mut count = 0;
while count < key_round.size {
match fs.read_node(self.block, key_round.offset as u64 + count as u64,
&mut content[count..key_round.size])? {
0 => break,
n => count += n
}
}
fn funmap(&mut self, address: usize, fs: &mut FileSystem<D>) -> Result<usize> {
if let Some(mut fmap) = self.fmaps.remove(&address) {
fmap.sync(fs)?;
let value = maps.insert(i, key_round, FmapValue {
buffer: content,
actual_size: count,
refcount: 1
});
self.fmap = Some((i, key_exact));
Ok(value.buffer.as_ptr() as usize + (key_exact.offset - key_round.offset))
}
fn funmap(&mut self, maps: &mut Fmaps, fs: &mut FileSystem<D>) -> Result<usize> {
self.sync_fmap(maps, fs)?;
if let Some((i, _)) = self.fmap.as_ref() {
let value = maps.index(*i);
let clear = {
let (_, value) = value.as_mut().expect("mapping dropped while still referenced");
value.refcount -= 1;
value.refcount == 0
};
if clear {
*value = None;
}
Ok(0)
} else {
Err(Error::new(EINVAL))
}
Ok(0)
}
fn fchmod(&mut self, mode: u16, fs: &mut FileSystem<D>) -> Result<usize> {
......@@ -428,8 +422,11 @@ impl<D: Disk> Resource<D> for FileResource {
Ok(0)
}
fn sync(&mut self, maps: &mut Fmaps, fs: &mut FileSystem<D>) -> Result<usize> {
self.sync_fmap(maps, fs)?;
fn sync(&mut self, fs: &mut FileSystem<D>) -> Result<usize> {
for fmap in self.fmaps.values_mut() {
fmap.sync(fs)?;
}
Ok(0)
}
......@@ -462,3 +459,11 @@ impl<D: Disk> Resource<D> for FileResource {
}
}
}
impl Drop for FileResource {
fn drop(&mut self) {
if ! self.fmaps.is_empty() {
eprintln!("redoxfs: file {} still has {} fmaps!", self.path, self.fmaps.len());
}
}
}
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::result::Result as StdResult;
use std::str;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::{SystemTime, UNIX_EPOCH};
......@@ -16,83 +15,13 @@ use filesystem::FileSystem;
use node::Node;
use super::resource::{Resource, DirResource, FileResource};
use super::spin::Mutex;
/// The size to round offset/len up to.
/// This ensures more fmaps can share the same memory even with different parameters.
const PAGE_SIZE: usize = 4096;
/// The max amount of fmaps that can be held simultaneously.
/// This restriction is here because we can under no circumstances reallocate,
/// that would invalidate previous mappings.
const FMAP_AMOUNT: usize = 1024;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct FmapKey {
pub block: u64,
pub offset: usize,
pub size: usize
}
impl FmapKey {
pub fn round(&self) -> FmapKey {
let remainder = self.size % PAGE_SIZE;
FmapKey {
block: self.block,
offset: self.offset - self.offset % PAGE_SIZE,
size: if remainder == 0 { self.size } else { self.size - remainder + PAGE_SIZE }
}
}
pub fn is_compatible(&self, other: &FmapKey) -> bool {
self.block == other.block
&& self.offset <= other.offset
&& self.offset + self.size >= other.offset + other.size
}
}
#[derive(Clone)]
pub struct FmapValue {
pub buffer: Vec<u8>,
/// The actual file length. Syncing only writes &buffer[..actual_size].
pub actual_size: usize,
pub refcount: usize
}
// NOTE: This can NOT reallocate. That would invalidate previous mappings.
pub struct Fmaps(Vec<Option<(FmapKey, FmapValue)>>);
impl Default for Fmaps {
fn default() -> Fmaps {
Fmaps(vec![None; FMAP_AMOUNT])
}
}
impl Fmaps {
pub fn find_compatible(&mut self, key: &FmapKey) -> StdResult<(usize, &mut (FmapKey, FmapValue)), Option<usize>> {
let mut first_empty = None;
for (i, entry) in self.0.iter_mut().enumerate() {
match entry {
None if first_empty.is_none() => first_empty = Some(i),
Some(entry) if entry.0.is_compatible(key) => return Ok((i, entry)),
_ => ()
}
}
Err(first_empty)
}
pub fn index(&mut self, index: usize) -> &mut Option<(FmapKey, FmapValue)> {
&mut self.0[index]
}
pub fn insert(&mut self, index: usize, key: FmapKey, value: FmapValue) -> &mut FmapValue {
let elem = &mut self.0[index];
assert!(elem.is_none());
*elem = Some((key, value));
&mut elem.as_mut().unwrap().1
}
}
pub struct FileScheme<D: Disk> {
name: String,
fs: RefCell<FileSystem<D>>,
next_id: AtomicUsize,
files: Mutex<BTreeMap<usize, Box<Resource<D>>>>,
fmaps: Mutex<Fmaps>
files: RefCell<BTreeMap<usize, Box<Resource<D>>>>,
fmap: RefCell<BTreeMap<usize, usize>>,
}
impl<D: Disk> FileScheme<D> {
......@@ -101,8 +30,8 @@ impl<D: Disk> FileScheme<D> {
name: name,
fs: RefCell::new(fs),
next_id: AtomicUsize::new(1),
files: Mutex::new(BTreeMap::new()),
fmaps: Mutex::new(Fmaps::default())