diff --git a/Cargo.lock b/Cargo.lock index c794fe8d5b..b55d02e62f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.19.0" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" dependencies = [ "gimli", ] @@ -61,9 +61,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" dependencies = [ "addr2line", "cc", @@ -112,9 +112,12 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "51f1226cd9da55587234753d1245dd5b132343ea240f26b6a9003d68706141ba" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -133,9 +136,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" dependencies = [ "libc", ] @@ -262,9 +265,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "libc" -version = "0.2.146" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "log" @@ -280,9 +283,9 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "miniz_oxide" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", ] @@ -295,9 +298,9 @@ checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" [[package]] name = "object" -version = "0.30.4" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" dependencies = [ "memchr", ] @@ -326,18 +329,18 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.28" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" dependencies = [ "proc-macro2", ] @@ -380,6 +383,11 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" +[[package]] +name = "range-tree" +version = "0.1.0" +source = "git+https://gitlab.redox-os.org/redox-os/range-tree.git#a1b3720c65cd3388def5f4c7fb32281380c78c0d" + [[package]] name = "rdrand" version = "0.4.0" @@ -407,8 +415,7 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#a525620c818a801bb7038e111b71033eff56a3ee" dependencies = [ "bitflags", ] @@ -435,6 +442,7 @@ dependencies = [ "getrandom", "libc", "log", + "range-tree", "redox_simple_endian", "redox_syscall 0.3.5", "seahash", @@ -445,9 +453,21 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.4" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294" dependencies = [ "aho-corasick", "memchr", @@ -456,9 +476,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" [[package]] name = "rustc-demangle" @@ -474,9 +494,9 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" [[package]] name = "subtle" @@ -547,9 +567,9 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-xid" diff --git a/Cargo.toml b/Cargo.toml index eac92abbb9..c3684407d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,8 @@ failure = "0.1.8" getrandom = { version = "0.2.5", optional = true } libc = "0.2" log = { version = "0.4.14", default-features = false, optional = true} -redox_syscall = "0.3" +redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } +range-tree = { git = "https://gitlab.redox-os.org/redox-os/range-tree.git" } seahash = { version = "4.1.0", default-features = false } termion = { version = "1.5.6", optional = true } uuid = { version = "0.5", default-features = false } @@ -54,7 +55,7 @@ features = [ ] [features] -default = ["std"] +default = ["std", "log"] force-soft = [ "aes/force-soft" ] diff --git a/src/bin/mount.rs b/src/bin/mount.rs index 4a9bbdb785..6a1bbd211b 100644 --- a/src/bin/mount.rs +++ b/src/bin/mount.rs @@ -1,3 +1,5 @@ +#![feature(int_roundings)] + extern crate libc; #[cfg(target_os = "redox")] @@ -90,14 +92,16 @@ fn bootloader_password() -> Option> { let mut password = Vec::with_capacity(size); unsafe { - let password_map = syscall::physmap(addr, size, syscall::PhysmapFlags::empty()) + let aligned_size = size.next_multiple_of(syscall::PAGE_SIZE); + + let password_map = syscall::physmap(addr, aligned_size, syscall::PhysmapFlags::empty()) .expect("failed to map REDOXFS_PASSWORD"); for i in 0..size { password.push(*((password_map + i) as *const u8)); } - let _ = syscall::physunmap(password_map); + let _ = syscall::funmap(password_map, aligned_size); } Some(password) } diff --git a/src/lib.rs b/src/lib.rs index 3e8b0f385a..e7b1f8d0a8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,8 @@ // Used often in generating redox_syscall errors #![allow(clippy::or_fun_call)] +#![feature(int_roundings)] + extern crate alloc; use core::sync::atomic::AtomicUsize; diff --git a/src/mount/redox/resource.rs b/src/mount/redox/resource.rs index d2a8430ee1..f89f95bfb7 100644 --- a/src/mount/redox/resource.rs +++ b/src/mount/redox/resource.rs @@ -1,8 +1,11 @@ use std::cmp::{max, min}; -use std::collections::BTreeMap; use std::slice; use std::time::{SystemTime, UNIX_EPOCH}; +use alloc::collections::BTreeMap; +use range_tree::RangeTree; + +use syscall::{MAP_PRIVATE, PAGE_SIZE, EBADFD}; use syscall::data::{Map, Stat, TimeSpec}; use syscall::error::{Error, Result, EBADF, EINVAL, EISDIR, ENOMEM, EPERM}; use syscall::flag::{ @@ -12,6 +15,8 @@ use syscall::flag::{ use crate::{Disk, Node, Transaction, TreePtr}; +pub type Fmaps = BTreeMap; + pub trait Resource { fn parent_ptr_opt(&self) -> Option>; @@ -29,9 +34,9 @@ pub trait Resource { fn seek(&mut self, offset: isize, whence: usize, tx: &mut Transaction) -> Result; - fn fmap(&mut self, map: &Map, tx: &mut Transaction) -> Result; + fn fmap(&mut self, fmaps: &mut Fmaps, flags: MapFlags, size: usize, offset: u64, tx: &mut Transaction) -> Result; - fn funmap(&mut self, address: usize, tx: &mut Transaction) -> Result; + fn funmap(&mut self, fmaps: &mut Fmaps, offset: u64, size: usize, tx: &mut Transaction) -> Result; fn fchmod(&mut self, mode: u16, tx: &mut Transaction) -> Result { let mut node = tx.read_tree(self.node_ptr())?; @@ -112,7 +117,7 @@ pub trait Resource { Ok(0) } - fn sync(&mut self, tx: &mut Transaction) -> Result; + fn sync(&mut self, fmaps: &mut Fmaps, tx: &mut Transaction) -> Result; fn truncate(&mut self, len: usize, tx: &mut Transaction) -> Result; @@ -203,10 +208,10 @@ impl Resource for DirResource { Ok(self.seek) } - fn fmap(&mut self, _map: &Map, _tx: &mut Transaction) -> Result { + fn fmap(&mut self, _fmaps: &mut Fmaps, _flags: MapFlags, _size: usize, _offset: u64, _tx: &mut Transaction) -> Result { Err(Error::new(EBADF)) } - fn funmap(&mut self, _address: usize, _tx: &mut Transaction) -> Result { + fn funmap(&mut self, _fmaps: &mut Fmaps, _offset: u64, _size: usize, _tx: &mut Transaction) -> Result { Err(Error::new(EBADF)) } @@ -218,7 +223,7 @@ impl Resource for DirResource { &self.path } - fn sync(&mut self, _tx: &mut Transaction) -> Result { + fn sync(&mut self, _fmaps: &mut Fmaps, _tx: &mut Transaction) -> Result { Err(Error::new(EBADF)) } @@ -231,68 +236,64 @@ impl Resource for DirResource { } } +#[derive(Debug)] pub struct Fmap { - node_ptr: TreePtr, - offset: usize, + rc: usize, flags: MapFlags, - data: &'static mut [u8], + last_page_tail: u16, } impl Fmap { pub unsafe fn new( node_ptr: TreePtr, - map: &Map, + flags: MapFlags, + unaligned_size: usize, + offset: u64, + base: *mut u8, tx: &mut Transaction, ) -> Result { - 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)); - } + let aligned_size = unaligned_size.next_multiple_of(syscall::PAGE_SIZE); + + let address = base.add(offset as usize); + //println!("ADDR {:p} {:p}", base, address); // Read buffer from disk let atime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); - let buf = slice::from_raw_parts_mut(address, map.size); + + let buf = slice::from_raw_parts_mut(address, unaligned_size); + let count = match tx.read_node( node_ptr, - map.offset as u64, + offset, buf, atime.as_secs(), atime.subsec_nanos(), ) { Ok(ok) => ok, Err(err) => { - free(address); + let _ = syscall::funmap(address as usize, aligned_size); return Err(err); } }; // Make sure remaining data is zeroed - for i in count..buf.len() { - buf[i] = 0; - } + buf[count..].fill(0_u8); Ok(Self { - node_ptr, - offset: map.offset, - flags: map.flags, - data: buf, + rc: 1, + flags, + last_page_tail: (unaligned_size % PAGE_SIZE) as u16, }) } - pub fn sync(&mut self, tx: &mut Transaction) -> Result<()> { + pub unsafe fn sync(&mut self, node_ptr: TreePtr, base: *mut u8, offset: u64, size: usize, tx: &mut Transaction) -> Result<()> { if self.flags & PROT_WRITE == PROT_WRITE { let mtime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); tx.write_node( - self.node_ptr, - self.offset as u64, - &self.data, + node_ptr, + offset, + unsafe { core::slice::from_raw_parts(base.add(offset as usize), size) }, mtime.as_secs(), mtime.subsec_nanos(), )?; @@ -301,18 +302,6 @@ impl Fmap { } } -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, parent_ptr_opt: Option>, @@ -320,7 +309,20 @@ pub struct FileResource { flags: usize, seek: isize, uid: u32, - fmaps: BTreeMap, +} +pub struct FileMmapInfo { + base: *mut u8, + ranges: RangeTree, + pub open_fds: usize, +} +impl Default for FileMmapInfo { + fn default() -> Self { + Self { + base: core::ptr::null_mut(), + ranges: RangeTree::new(), + open_fds: 0, + } + } } impl FileResource { @@ -338,7 +340,6 @@ impl FileResource { flags, seek: 0, uid, - fmaps: BTreeMap::new(), } } } @@ -364,7 +365,6 @@ impl Resource for FileResource { flags: self.flags, seek: self.seek, uid: self.uid, - fmaps: BTreeMap::new(), })) } @@ -423,30 +423,91 @@ impl Resource for FileResource { Ok(self.seek) } - fn fmap(&mut self, map: &Map, tx: &mut Transaction) -> Result { + fn fmap(&mut self, fmaps: &mut Fmaps, flags: MapFlags, unaligned_size: usize, offset: u64, tx: &mut Transaction) -> Result { + //dbg!(&self.fmaps); let accmode = self.flags & O_ACCMODE; - if map.flags.contains(PROT_READ) && !(accmode == O_RDWR || accmode == O_RDONLY) { + if flags.contains(PROT_READ) && !(accmode == O_RDWR || accmode == O_RDONLY) { return Err(Error::new(EBADF)); } - if map.flags.contains(PROT_WRITE) && !(accmode == O_RDWR || accmode == O_WRONLY) { + if flags.contains(PROT_WRITE) && !(accmode == O_RDWR || accmode == O_WRONLY) { return Err(Error::new(EBADF)); } - //TODO: PROT_EXEC? - let map = unsafe { Fmap::new(self.node_ptr, map, tx)? }; - let address = map.data.as_ptr() as usize; - self.fmaps.insert(address, map); - Ok(address) + let aligned_size = unaligned_size.next_multiple_of(PAGE_SIZE); + + // TODO: PROT_EXEC? It is however unenforcable without restricting anonymous mmap, since a + // program can always map anonymous RW-, read from a file, then remap as R-E. But it might + // be usable as a hint, prohibiting direct executable mmaps at least. + + // TODO: Pass entry directory to Resource trait functions, since the node_ptr can be + // obtained by the caller. + let fmap_info = fmaps.get_mut(&self.node_ptr.id()).ok_or(Error::new(EBADFD))?; + + let max_offset = fmap_info.ranges.end(); + if offset + aligned_size as u64 > max_offset { + if fmap_info.base.is_null() { + fmap_info.base = unsafe { + syscall::fmap(!0, &Map { + size: offset as usize + aligned_size, + // PRIVATE/SHARED doesn't matter once the pages are passed in the fmap + // handler. + flags: MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_PRIVATE, + + offset: 0, + address: 0, + })? as *mut u8 + }; + } else { + let new_size = (offset as usize + aligned_size).next_multiple_of(PAGE_SIZE); + let old_size = max_offset as usize; + + fmap_info.base = unsafe { + syscall::syscall5(syscall::SYS_MREMAP, fmap_info.base as usize, old_size, 0, new_size, syscall::MremapFlags::empty().bits() | (PROT_READ | PROT_WRITE).bits())? as *mut u8 + }; + } + } + + let affected_fmaps = fmap_info.ranges.remove_and_unused(offset..offset + aligned_size as u64); + + for (range, v_opt) in affected_fmaps { + //dbg!(&range); + if let Some(mut fmap) = v_opt { + fmap.rc += 1; + fmap.flags |= flags; + + fmap_info.ranges.insert(range.start, range.end - range.start, fmap); + } else { + let map = unsafe { Fmap::new(self.node_ptr, flags, unaligned_size, offset, fmap_info.base, tx)? }; + fmap_info.ranges.insert(offset, aligned_size as u64, map); + } + } + //dbg!(&self.fmaps); + + Ok(fmap_info.base as usize + offset as usize) } - fn funmap(&mut self, address: usize, tx: &mut Transaction) -> Result { - if let Some(mut fmap) = self.fmaps.remove(&address) { - fmap.sync(tx)?; + fn funmap(&mut self, fmaps: &mut Fmaps, offset: u64, size: usize, tx: &mut Transaction) -> Result { + let fmap_info = fmaps.get_mut(&self.node_ptr.id()).ok_or(Error::new(EBADFD))?; - Ok(0) - } else { - Err(Error::new(EINVAL)) + //dbg!(&self.fmaps); + //dbg!(self.fmaps.conflicts(offset..offset + size as u64).collect::>()); + let mut affected_fmaps = fmap_info.ranges.remove(offset..offset + size as u64); + + for (range, mut fmap) in affected_fmaps { + fmap.rc = fmap.rc.checked_sub(1).unwrap(); + + //log::info!("SYNCING {}..{}", range.start, range.end); + unsafe { + fmap.sync(self.node_ptr, fmap_info.base, range.start, (range.end - range.start) as usize, tx)?; + } + + if fmap.rc > 0 { + fmap_info.ranges.insert(range.start, range.end - range.start, fmap); + } } + //dbg!(&self.fmaps); + + Ok(0) } fn fcntl(&mut self, cmd: usize, arg: usize) -> Result { @@ -464,9 +525,13 @@ impl Resource for FileResource { &self.path } - fn sync(&mut self, tx: &mut Transaction) -> Result { - for fmap in self.fmaps.values_mut() { - fmap.sync(tx)?; + fn sync(&mut self, fmaps: &mut Fmaps, tx: &mut Transaction) -> Result { + if let Some(fmap_info) = fmaps.get_mut(&self.node_ptr.id()) { + for (range, fmap) in fmap_info.ranges.iter_mut() { + unsafe { + fmap.sync(self.node_ptr, fmap_info.base, range.start, (range.end - range.start) as usize, tx)?; + } + } } Ok(0) @@ -521,6 +586,7 @@ impl Resource for FileResource { impl Drop for FileResource { fn drop(&mut self) { + /* if !self.fmaps.is_empty() { eprintln!( "redoxfs: file {} still has {} fmaps!", @@ -528,5 +594,44 @@ impl Drop for FileResource { self.fmaps.len() ); } + */ + } +} + +impl range_tree::Value for Fmap { + type K = u64; + + fn try_merge_forward(self, other: &Self) -> core::result::Result { + if self.rc == other.rc && self.flags == other.flags && self.last_page_tail == 0 { + Ok(self) + } else { + Err(self) + } + } + fn try_merge_backwards(self, other: &Self) -> core::result::Result { + if self.rc == other.rc && self.flags == other.flags && other.last_page_tail == 0 { + Ok(self) + } else { + Err(self) + } + } + fn split(self, prev_range: Option>, range: core::ops::Range, next_range: Option>) -> (Option, Self, Option) { + ( + prev_range.map(|range| Fmap { + rc: self.rc, + flags: self.flags, + last_page_tail: 0, + }), + Fmap { + rc: self.rc, + flags: self.flags, + last_page_tail: if next_range.is_none() { self.last_page_tail } else { 0 }, + }, + next_range.map(|range| Fmap { + rc: self.rc, + flags: self.flags, + last_page_tail: self.last_page_tail, + }), + ) } } diff --git a/src/mount/redox/scheme.rs b/src/mount/redox/scheme.rs index 8cb1091d89..67c7bac6ab 100644 --- a/src/mount/redox/scheme.rs +++ b/src/mount/redox/scheme.rs @@ -3,14 +3,15 @@ use std::str; use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::{SystemTime, UNIX_EPOCH}; +use syscall::{EBADFD, MunmapFlags}; use syscall::data::{Map, Stat, StatVfs, TimeSpec}; use syscall::error::{ Error, Result, EACCES, EBADF, EBUSY, EEXIST, EINVAL, EISDIR, ELOOP, ENOENT, ENOTDIR, ENOTEMPTY, EPERM, EXDEV, }; use syscall::flag::{ - EventFlags, MODE_PERM, O_ACCMODE, O_CREAT, O_DIRECTORY, O_EXCL, O_NOFOLLOW, O_RDONLY, O_RDWR, - O_STAT, O_SYMLINK, O_TRUNC, O_WRONLY, + EventFlags, MapFlags, MODE_PERM, O_ACCMODE, O_CREAT, O_DIRECTORY, O_EXCL, O_NOFOLLOW, O_RDONLY, + O_RDWR, O_STAT, O_SYMLINK, O_TRUNC, O_WRONLY, }; use syscall::scheme::SchemeMut; @@ -23,14 +24,14 @@ pub struct FileScheme { fs: FileSystem, next_id: AtomicUsize, files: BTreeMap>>, - fmap: BTreeMap, + fmap: super::resource::Fmaps, } impl FileScheme { pub fn new(name: String, fs: FileSystem) -> FileScheme { FileScheme { - name: name, - fs: fs, + name, + fs, next_id: AtomicUsize::new(1), files: BTreeMap::new(), fmap: BTreeMap::new(), @@ -400,6 +401,8 @@ impl SchemeMut for FileScheme { } } }; + self.fmap.entry(resource.node_ptr().id()).or_insert_with(Default::default).open_fds += 1; + let id = self.next_id.fetch_add(1, Ordering::SeqCst); self.files.insert(id, resource); @@ -533,6 +536,7 @@ impl SchemeMut for FileScheme { return Err(Error::new(EBADF)); }; + self.fmap.get_mut(&resource.node_ptr().id()).ok_or(Error::new(EBADFD))?.open_fds += 1; let id = self.next_id.fetch_add(1, Ordering::SeqCst); self.files.insert(id, resource); @@ -755,11 +759,10 @@ impl SchemeMut for FileScheme { fn fsync(&mut self, id: usize) -> Result { // println!("Fsync {}", id); - if let Some(file) = self.files.get_mut(&id) { - self.fs.tx(|tx| file.sync(tx)) - } else { - Err(Error::new(EBADF)) - } + let file = self.files.get_mut(&id).ok_or(Error::new(EBADF))?; + let fmaps = &mut self.fmap; + + self.fs.tx(|tx| file.sync(fmaps, tx)) } fn ftruncate(&mut self, id: usize, len: usize) -> Result { @@ -780,49 +783,31 @@ impl SchemeMut for FileScheme { } } - fn fmap(&mut self, id: usize, map: &Map) -> Result { - // println!("Fmap {}, {:?}", id, map); - if let Some(file) = self.files.get_mut(&id) { - let address = self.fs.tx(|tx| file.fmap(map, tx))?; - self.fmap.insert(address, id); - Ok(address) - } else { - Err(Error::new(EBADF)) - } - } + fn mmap_prep(&mut self, id: usize, offset: u64, size: usize, flags: MapFlags) -> Result { + println!("Mmap {}, {:?} {} {}", id, flags, size, offset); + let file = self.files.get_mut(&id).ok_or(Error::new(EBADF))?; + let fmaps = &mut self.fmap; - fn funmap_old(&mut self, address: usize) -> Result { - if let Some(id) = self.fmap.remove(&address) { - if let Some(file) = self.files.get_mut(&id) { - self.fs.tx(|tx| file.funmap(address, tx)) - } else { - Err(Error::new(EINVAL)) - } - } else { - Err(Error::new(EINVAL)) - } + self.fs.tx(|tx| file.fmap(fmaps, flags, size, offset, tx)) } + fn munmap(&mut self, id: usize, offset: u64, size: usize, flags: MunmapFlags) -> Result { + println!("Munmap {}, {} {}", id, size, offset); + let file = self.files.get_mut(&id).ok_or(Error::new(EBADF))?; + let fmaps = &mut self.fmap; - //TODO: implement (length is ignored!) - fn funmap(&mut self, address: usize, length: usize) -> Result { - println!("redoxfs: funmap 0x{:X}, {}", address, length); - if let Some(id) = self.fmap.remove(&address) { - if let Some(file) = self.files.get_mut(&id) { - self.fs.tx(|tx| file.funmap(address, tx)) - } else { - Err(Error::new(EINVAL)) - } - } else { - Err(Error::new(EINVAL)) - } + self.fs.tx(|tx| file.funmap(fmaps, offset, size, tx)) } fn close(&mut self, id: usize) -> Result { // println!("Close {}", id); - if self.files.remove(&id).is_some() { - Ok(0) - } else { - Err(Error::new(EBADF)) - } + let file = self.files.remove(&id).ok_or(Error::new(EBADF))?; + let file_info = self.fmap.get_mut(&file.node_ptr().id()).ok_or(Error::new(EBADFD))?; + + file_info.open_fds = file_info.open_fds.checked_sub(1).expect("open_fds not tracked correctly"); + + // TODO: If open_fds reaches zero and there are no hardlinks (directory entries) to any + // particular inode, remove that inode here. + + Ok(0) } }