diff --git a/src/scheme/root.rs b/src/scheme/root.rs index 27cbcecb4498dec31634ef7c17963dfb340b8070..13f9089110e63ecc444caba7245772fb7e98b9f8 100644 --- a/src/scheme/root.rs +++ b/src/scheme/root.rs @@ -140,6 +140,32 @@ impl Scheme for RootScheme { } } + fn unlink(&self, path: &[u8], uid: u32, _gid: u32) -> Result<usize> { + let path_utf8 = str::from_utf8(path).or(Err(Error::new(ENOENT)))?; + let path_trimmed = path_utf8.trim_matches('/'); + + if uid == 0 { + let inner = { + let handles = self.handles.read(); + handles.iter().find_map(|(_id, handle)| { + match handle { + Handle::Scheme(inner) => { + if path_trimmed.as_bytes() == inner.name.as_ref() { + return Some(inner.clone()); + } + }, + _ => (), + } + None + }).ok_or(Error::new(ENOENT))? + }; + + inner.unmount() + } else { + Err(Error::new(EACCES)) + } + } + fn read(&self, file: usize, buf: &mut [u8]) -> Result<usize> { let handle = { let handles = self.handles.read(); diff --git a/src/scheme/user.rs b/src/scheme/user.rs index 6c31edfcb3db48eedf63b414873b15fc09c52cf6..11a86200261d6f17c159f8db4405f66d619eaf80 100644 --- a/src/scheme/user.rs +++ b/src/scheme/user.rs @@ -1,7 +1,7 @@ use alloc::sync::{Arc, Weak}; use alloc::boxed::Box; use alloc::collections::BTreeMap; -use core::sync::atomic::{AtomicU64, Ordering}; +use core::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use core::{mem, slice, usize}; use spin::{Mutex, RwLock}; @@ -31,7 +31,8 @@ pub struct UserInner { todo: WaitQueue<Packet>, fmap: Mutex<BTreeMap<u64, (Weak<RwLock<Context>>, FileDescriptor, Map)>>, funmap: Mutex<BTreeMap<usize, usize>>, - done: WaitMap<u64, usize> + done: WaitMap<u64, usize>, + unmounting: AtomicBool, } impl UserInner { @@ -47,10 +48,25 @@ impl UserInner { todo: WaitQueue::new(), fmap: Mutex::new(BTreeMap::new()), funmap: Mutex::new(BTreeMap::new()), - done: WaitMap::new() + done: WaitMap::new(), + unmounting: AtomicBool::new(false), } } + pub fn unmount(&self) -> Result<usize> { + // First, block new requests and prepare to return EOF + self.unmounting.store(true, Ordering::SeqCst); + + // Wake up any blocked scheme handler + unsafe { self.todo.condition.notify_signal() }; + + // Tell the scheme handler to read + event::trigger(self.root_id, self.handle_id, EVENT_READ); + + //TODO: wait for all todo and done to be processed? + Ok(0) + } + pub fn call(&self, a: usize, b: usize, c: usize, d: usize) -> Result<usize> { let (pid, uid, gid) = { let contexts = context::contexts(); @@ -72,6 +88,10 @@ impl UserInner { } fn call_inner(&self, packet: Packet) -> Result<usize> { + if self.unmounting.load(Ordering::SeqCst) { + return Err(Error::new(ENODEV)); + } + let id = packet.id; self.todo.send(packet); @@ -172,11 +192,36 @@ impl UserInner { } pub fn read(&self, buf: &mut [u8]) -> Result<usize> { - let packet_buf = unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut Packet, buf.len()/mem::size_of::<Packet>()) }; - self.todo - .receive_into(packet_buf, self.flags & O_NONBLOCK != O_NONBLOCK) - .map(|count| count * mem::size_of::<Packet>()) - .ok_or(Error::new(EINTR)) + let packet_buf = unsafe { slice::from_raw_parts_mut( + buf.as_mut_ptr() as *mut Packet, + buf.len()/mem::size_of::<Packet>()) + }; + + // If O_NONBLOCK is used, do not block + let nonblock = self.flags & O_NONBLOCK == O_NONBLOCK; + // If unmounting, do not block so that EOF can be returned immediately + let unmounting = self.unmounting.load(Ordering::SeqCst); + let block = !(nonblock || unmounting); + if let Some(count) = self.todo.receive_into(packet_buf, block) { + if count > 0 { + // If we received requests, return them to the scheme handler + Ok(count * mem::size_of::<Packet>()) + } else if unmounting { + // If there were no requests and we were unmounting, return EOF + Ok(0) + } else { + // If there were no requests and O_NONBLOCK was used, return EAGAIN + Err(Error::new(EAGAIN)) + } + } else if self.unmounting.load(Ordering::SeqCst) { + // If we are unmounting and there are no pending requests, return EOF + // Unmounting is read again because the previous value + // may have changed since we first blocked for packets + Ok(0) + } else { + // A signal was received, return EINTR + Err(Error::new(EINTR)) + } } pub fn write(&self, buf: &[u8]) -> Result<usize> {