From 5db0da52e2ddcc6087f2d632c2d4c3c169511647 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 20 Jul 2023 16:58:58 +0200 Subject: [PATCH 1/4] WIP: Use improved mmap interface. --- Cargo.lock | 68 +++++++---- Cargo.toml | 7 +- src/bin/mount.rs | 8 +- src/lib.rs | 2 + src/mount/redox/resource.rs | 228 ++++++++++++++++++++++++++---------- src/mount/redox/scheme.rs | 41 +++---- 6 files changed, 236 insertions(+), 118 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c794fe8d5b..f37337165f 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", @@ -133,9 +133,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 +262,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 +280,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 +295,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 +326,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.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" dependencies = [ "proc-macro2", ] @@ -380,6 +380,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#9dd8927149a066ac958acee1369be4f465cb7851" + [[package]] name = "rdrand" version = "0.4.0" @@ -407,8 +412,6 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ "bitflags", ] @@ -435,6 +438,7 @@ dependencies = [ "getrandom", "libc", "log", + "range-tree", "redox_simple_endian", "redox_syscall 0.3.5", "seahash", @@ -445,9 +449,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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" dependencies = [ "aho-corasick", "memchr", @@ -456,9 +472,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 +490,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 +563,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..9883748b2c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,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" +# range-tree = { path = "../../../../../range-tree" } +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 +56,7 @@ features = [ ] [features] -default = ["std"] +default = ["std", "log"] force-soft = [ "aes/force-soft" ] @@ -72,3 +74,6 @@ std = [ fuser = { version = "0.12.0", optional = true } libc = { version = "0.2", optional = true } time = { version = "0.1", optional = true } + +[patch.crates-io] +redox_syscall = { path = "../../kernel/source/syscall" } 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..3bbfff96df 100644 --- a/src/mount/redox/resource.rs +++ b/src/mount/redox/resource.rs @@ -1,8 +1,10 @@ use std::cmp::{max, min}; -use std::collections::BTreeMap; use std::slice; use std::time::{SystemTime, UNIX_EPOCH}; +use range_tree::RangeTree; + +use syscall::{MAP_PRIVATE, PAGE_SIZE}; use syscall::data::{Map, Stat, TimeSpec}; use syscall::error::{Error, Result, EBADF, EINVAL, EISDIR, ENOMEM, EPERM}; use syscall::flag::{ @@ -29,9 +31,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, flags: MapFlags, size: usize, offset: u64, tx: &mut Transaction) -> Result; - fn funmap(&mut self, address: usize, tx: &mut Transaction) -> Result; + fn funmap(&mut self, 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())?; @@ -203,10 +205,10 @@ impl Resource for DirResource { Ok(self.seek) } - fn fmap(&mut self, _map: &Map, _tx: &mut Transaction) -> Result { + fn fmap(&mut self, _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, _offset: u64, _size: usize, _tx: &mut Transaction) -> Result { Err(Error::new(EBADF)) } @@ -231,68 +233,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}", 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 +299,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 +306,8 @@ pub struct FileResource { flags: usize, seek: isize, uid: u32, - fmaps: BTreeMap, + base: *mut u8, + fmaps: RangeTree, } impl FileResource { @@ -337,8 +324,9 @@ impl FileResource { node_ptr, flags, seek: 0, + base: core::ptr::null_mut(), uid, - fmaps: BTreeMap::new(), + fmaps: RangeTree::new(), } } } @@ -364,7 +352,8 @@ impl Resource for FileResource { flags: self.flags, seek: self.seek, uid: self.uid, - fmaps: BTreeMap::new(), + fmaps: RangeTree::new(), + base: core::ptr::null_mut(), })) } @@ -423,30 +412,101 @@ impl Resource for FileResource { Ok(self.seek) } - fn fmap(&mut self, map: &Map, tx: &mut Transaction) -> Result { + fn fmap(&mut self, 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. + + let max_offset = self.fmaps.end(); + if offset + aligned_size as u64 > max_offset { + if self.base.is_null() { + self.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; + let common_size = std::cmp::min(new_size, old_size); + + if new_size > old_size { + unsafe { + syscall::fmap(!0, &Map { + size: new_size - old_size, + flags: MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_PRIVATE, + offset: old_size, + address: 0, + })?; + } + } else if old_size > new_size { + unsafe { + syscall::funmap(old_size, old_size - new_size)?; + } + } + + self.base = unsafe { + syscall::syscall5(syscall::SYS_MREMAP, self.base as usize, common_size, 0, common_size, syscall::MremapFlags::empty().bits())? as *mut u8 + }; + } + } + + let affected_fmaps = self.fmaps.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; + + self.fmaps.insert(range.start, range.end - range.start, fmap); + } else { + let map = unsafe { Fmap::new(self.node_ptr, flags, unaligned_size, offset, self.base, tx)? }; + self.fmaps.insert(offset, aligned_size as u64, map); + } + } + //dbg!(&self.fmaps); + + Ok(self.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, offset: u64, size: usize, tx: &mut Transaction) -> Result { + //dbg!(&self.fmaps); + //dbg!(self.fmaps.conflicts(offset..offset + size as u64).collect::>()); + let mut affected_fmaps = self.fmaps.remove(offset..offset + size as u64); - Ok(0) - } else { - Err(Error::new(EINVAL)) + 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, self.base, range.start, (range.end - range.start) as usize, tx)?; + } + + if fmap.rc > 0 { + self.fmaps.insert(range.start, range.end - range.start, fmap); + } } + //dbg!(&self.fmaps); + + Ok(0) } fn fcntl(&mut self, cmd: usize, arg: usize) -> Result { @@ -465,8 +525,10 @@ impl Resource for FileResource { } fn sync(&mut self, tx: &mut Transaction) -> Result { - for fmap in self.fmaps.values_mut() { - fmap.sync(tx)?; + for (range, fmap) in self.fmaps.iter_mut() { + unsafe { + fmap.sync(self.node_ptr, self.base, range.start, (range.end - range.start) as usize, tx)?; + } } Ok(0) @@ -530,3 +592,41 @@ impl Drop for FileResource { } } } + +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..660812ce97 100644 --- a/src/mount/redox/scheme.rs +++ b/src/mount/redox/scheme.rs @@ -9,8 +9,8 @@ use syscall::error::{ 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,7 +23,7 @@ pub struct FileScheme { fs: FileSystem, next_id: AtomicUsize, files: BTreeMap>>, - fmap: BTreeMap, + fmap: BTreeMap, } impl FileScheme { @@ -780,29 +780,20 @@ 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 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)) - } + fn mmap_prep(&mut self, id: usize, flags: MapFlags, size: usize, offset: u64) -> Result { + println!("Mmap {}, {:?} {} {}", id, flags, size, offset); + let file = self.files.get_mut(&id).ok_or(Error::new(EBADF))?; + + self.fs.tx(|tx| file.fmap(flags, size, offset, tx)) + } + fn munmap(&mut self, id: usize, size: usize, offset: u64) -> Result { + println!("Munmap {}, {} {}", id, size, offset); + let file = self.files.get_mut(&id).ok_or(Error::new(EINVAL))?; + + self.fs.tx(|tx| file.funmap(offset, size, tx)) } + /* //TODO: implement (length is ignored!) fn funmap(&mut self, address: usize, length: usize) -> Result { println!("redoxfs: funmap 0x{:X}, {}", address, length); @@ -815,7 +806,7 @@ impl SchemeMut for FileScheme { } else { Err(Error::new(EINVAL)) } - } + }*/ fn close(&mut self, id: usize) -> Result { // println!("Close {}", id); From ae1f15a4490a38fd4e26361c860f9236f1a9c618 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 26 Jul 2023 16:06:53 +0200 Subject: [PATCH 2/4] Offset-based file mmap. --- src/mount/redox/resource.rs | 83 +++++++++++++++++++++++-------------- src/mount/redox/scheme.rs | 58 ++++++++++++-------------- 2 files changed, 78 insertions(+), 63 deletions(-) diff --git a/src/mount/redox/resource.rs b/src/mount/redox/resource.rs index 3bbfff96df..2d9d8e7ca6 100644 --- a/src/mount/redox/resource.rs +++ b/src/mount/redox/resource.rs @@ -2,9 +2,10 @@ use std::cmp::{max, min}; use std::slice; use std::time::{SystemTime, UNIX_EPOCH}; +use alloc::collections::BTreeMap; use range_tree::RangeTree; -use syscall::{MAP_PRIVATE, PAGE_SIZE}; +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::{ @@ -14,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>; @@ -31,9 +34,9 @@ pub trait Resource { fn seek(&mut self, offset: isize, whence: usize, tx: &mut Transaction) -> Result; - fn fmap(&mut self, flags: MapFlags, size: usize, offset: u64, 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, offset: u64, size: 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())?; @@ -114,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; @@ -205,10 +208,10 @@ impl Resource for DirResource { Ok(self.seek) } - fn fmap(&mut self, _flags: MapFlags, _size: usize, _offset: u64, _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, _offset: u64, _size: usize, _tx: &mut Transaction) -> Result { + fn funmap(&mut self, _fmaps: &mut Fmaps, _offset: u64, _size: usize, _tx: &mut Transaction) -> Result { Err(Error::new(EBADF)) } @@ -220,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)) } @@ -306,8 +309,20 @@ pub struct FileResource { flags: usize, seek: isize, uid: u32, +} +pub struct FileMmapInfo { base: *mut u8, - fmaps: RangeTree, + 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 { @@ -324,9 +339,7 @@ impl FileResource { node_ptr, flags, seek: 0, - base: core::ptr::null_mut(), uid, - fmaps: RangeTree::new(), } } } @@ -352,8 +365,6 @@ impl Resource for FileResource { flags: self.flags, seek: self.seek, uid: self.uid, - fmaps: RangeTree::new(), - base: core::ptr::null_mut(), })) } @@ -412,7 +423,7 @@ impl Resource for FileResource { Ok(self.seek) } - fn fmap(&mut self, flags: MapFlags, unaligned_size: usize, offset: u64, 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 flags.contains(PROT_READ) && !(accmode == O_RDWR || accmode == O_RDONLY) { @@ -428,10 +439,14 @@ impl Resource for FileResource { // 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. - let max_offset = self.fmaps.end(); + // 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 self.base.is_null() { - self.base = unsafe { + 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 @@ -462,13 +477,13 @@ impl Resource for FileResource { } } - self.base = unsafe { - syscall::syscall5(syscall::SYS_MREMAP, self.base as usize, common_size, 0, common_size, syscall::MremapFlags::empty().bits())? as *mut u8 + fmap_info.base = unsafe { + syscall::syscall5(syscall::SYS_MREMAP, fmap_info.base as usize, common_size, 0, common_size, syscall::MremapFlags::empty().bits())? as *mut u8 }; } } - let affected_fmaps = self.fmaps.remove_and_unused(offset..offset + aligned_size as u64); + let affected_fmaps = fmap_info.ranges.remove_and_unused(offset..offset + aligned_size as u64); for (range, v_opt) in affected_fmaps { //dbg!(&range); @@ -476,32 +491,34 @@ impl Resource for FileResource { fmap.rc += 1; fmap.flags |= flags; - self.fmaps.insert(range.start, range.end - range.start, fmap); + fmap_info.ranges.insert(range.start, range.end - range.start, fmap); } else { - let map = unsafe { Fmap::new(self.node_ptr, flags, unaligned_size, offset, self.base, tx)? }; - self.fmaps.insert(offset, aligned_size as u64, map); + 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(self.base as usize + offset as usize) + Ok(fmap_info.base as usize + offset as usize) } - fn funmap(&mut self, offset: u64, size: usize, tx: &mut Transaction) -> Result { + 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))?; + //dbg!(&self.fmaps); //dbg!(self.fmaps.conflicts(offset..offset + size as u64).collect::>()); - let mut affected_fmaps = self.fmaps.remove(offset..offset + size as u64); + 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, self.base, range.start, (range.end - range.start) as usize, tx)?; + fmap.sync(self.node_ptr, fmap_info.base, range.start, (range.end - range.start) as usize, tx)?; } if fmap.rc > 0 { - self.fmaps.insert(range.start, range.end - range.start, fmap); + fmap_info.ranges.insert(range.start, range.end - range.start, fmap); } } //dbg!(&self.fmaps); @@ -524,10 +541,12 @@ impl Resource for FileResource { &self.path } - fn sync(&mut self, tx: &mut Transaction) -> Result { - for (range, fmap) in self.fmaps.iter_mut() { - unsafe { - fmap.sync(self.node_ptr, self.base, range.start, (range.end - range.start) as usize, 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)?; + } } } @@ -583,6 +602,7 @@ impl Resource for FileResource { impl Drop for FileResource { fn drop(&mut self) { + /* if !self.fmaps.is_empty() { eprintln!( "redoxfs: file {} still has {} fmaps!", @@ -590,6 +610,7 @@ impl Drop for FileResource { self.fmaps.len() ); } + */ } } diff --git a/src/mount/redox/scheme.rs b/src/mount/redox/scheme.rs index 660812ce97..89fd88d3d8 100644 --- a/src/mount/redox/scheme.rs +++ b/src/mount/redox/scheme.rs @@ -3,6 +3,7 @@ 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, @@ -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,40 +783,31 @@ impl SchemeMut for FileScheme { } } - fn mmap_prep(&mut self, id: usize, flags: MapFlags, size: usize, offset: u64) -> Result { + 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; - self.fs.tx(|tx| file.fmap(flags, size, offset, tx)) + self.fs.tx(|tx| file.fmap(fmaps, flags, size, offset, tx)) } - fn munmap(&mut self, id: usize, size: usize, offset: u64) -> Result { + 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(EINVAL))?; + let fmaps = &mut self.fmap; - self.fs.tx(|tx| file.funmap(offset, size, tx)) + self.fs.tx(|tx| file.funmap(fmaps, offset, size, tx)) } - /* - //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)) - } - }*/ - 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) } } From 7f8a2e467eb33d9a16ffbfef2a3ebb2181df5df1 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 2 Aug 2023 15:28:35 +0200 Subject: [PATCH 3/4] Update dependencies. --- Cargo.lock | 18 +++++++++++------- Cargo.toml | 6 +----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f37337165f..b55d02e62f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" @@ -335,9 +338,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.31" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" dependencies = [ "proc-macro2", ] @@ -383,7 +386,7 @@ checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" [[package]] name = "range-tree" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/range-tree.git#9dd8927149a066ac958acee1369be4f465cb7851" +source = "git+https://gitlab.redox-os.org/redox-os/range-tree.git#a1b3720c65cd3388def5f4c7fb32281380c78c0d" [[package]] name = "rdrand" @@ -412,6 +415,7 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.3.5" +source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#a525620c818a801bb7038e111b71033eff56a3ee" dependencies = [ "bitflags", ] @@ -461,9 +465,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" +checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294" dependencies = [ "aho-corasick", "memchr", diff --git a/Cargo.toml b/Cargo.toml index 9883748b2c..c3684407d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,8 +39,7 @@ 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" -# range-tree = { path = "../../../../../range-tree" } +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 } @@ -74,6 +73,3 @@ std = [ fuser = { version = "0.12.0", optional = true } libc = { version = "0.2", optional = true } time = { version = "0.1", optional = true } - -[patch.crates-io] -redox_syscall = { path = "../../kernel/source/syscall" } From 6234d76e8dcc358e328cafe2d49096824f5edc87 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 3 Aug 2023 12:38:19 +0200 Subject: [PATCH 4/4] Fix mremap usage. --- src/mount/redox/resource.rs | 20 ++------------------ src/mount/redox/scheme.rs | 2 +- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/src/mount/redox/resource.rs b/src/mount/redox/resource.rs index 2d9d8e7ca6..f89f95bfb7 100644 --- a/src/mount/redox/resource.rs +++ b/src/mount/redox/resource.rs @@ -256,7 +256,7 @@ impl Fmap { let aligned_size = unaligned_size.next_multiple_of(syscall::PAGE_SIZE); let address = base.add(offset as usize); - println!("ADDR {:p}", address); + //println!("ADDR {:p} {:p}", base, address); // Read buffer from disk let atime = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); @@ -460,25 +460,9 @@ impl Resource for FileResource { } else { let new_size = (offset as usize + aligned_size).next_multiple_of(PAGE_SIZE); let old_size = max_offset as usize; - let common_size = std::cmp::min(new_size, old_size); - - if new_size > old_size { - unsafe { - syscall::fmap(!0, &Map { - size: new_size - old_size, - flags: MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_PRIVATE, - offset: old_size, - address: 0, - })?; - } - } else if old_size > new_size { - unsafe { - syscall::funmap(old_size, old_size - new_size)?; - } - } fmap_info.base = unsafe { - syscall::syscall5(syscall::SYS_MREMAP, fmap_info.base as usize, common_size, 0, common_size, syscall::MremapFlags::empty().bits())? as *mut u8 + 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 }; } } diff --git a/src/mount/redox/scheme.rs b/src/mount/redox/scheme.rs index 89fd88d3d8..67c7bac6ab 100644 --- a/src/mount/redox/scheme.rs +++ b/src/mount/redox/scheme.rs @@ -792,7 +792,7 @@ impl SchemeMut for FileScheme { } 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(EINVAL))?; + let file = self.files.get_mut(&id).ok_or(Error::new(EBADF))?; let fmaps = &mut self.fmap; self.fs.tx(|tx| file.funmap(fmaps, offset, size, tx))