diff --git a/src/context/file.rs b/src/context/file.rs index fb87a3c470..fd882e92ee 100644 --- a/src/context/file.rs +++ b/src/context/file.rs @@ -35,10 +35,10 @@ impl FileDescription { pub fn try_close(self) -> Result<()> { event::unregister_file(self.scheme, self.number); - let scheme = Arc::clone( - scheme::schemes() - .get(self.scheme).ok_or(Error::new(EBADF))? - ); + let scheme = scheme::schemes() + .get(self.scheme).ok_or(Error::new(EBADF))? + .clone(); + scheme.close(self.number) } } diff --git a/src/context/memory.rs b/src/context/memory.rs index 90f1f0be2c..6f0324f3a3 100644 --- a/src/context/memory.rs +++ b/src/context/memory.rs @@ -53,7 +53,7 @@ impl UnmapResult { }; let funmap_result = crate::scheme::schemes() - .get(scheme_id).map(Arc::clone).ok_or(Error::new(ENODEV)) + .get(scheme_id).cloned().ok_or(Error::new(ENODEV)) .and_then(|scheme| scheme.kfunmap(number, base_offset, self.size, self.flags)); if let Ok(fd) = Arc::try_unwrap(description) { diff --git a/src/event.rs b/src/event.rs index dbef4bfa17..300a59f272 100644 --- a/src/event.rs +++ b/src/event.rs @@ -151,11 +151,9 @@ pub fn sync(reg_key: RegKey) -> Result { } } - let scheme = { - let schemes = scheme::schemes(); - let scheme = schemes.get(reg_key.scheme).ok_or(Error::new(EBADF))?; - Arc::clone(scheme) - }; + let scheme = scheme::schemes() + .get(reg_key.scheme).ok_or(Error::new(EBADF))? + .clone(); scheme.fevent(reg_key.number, flags) } diff --git a/src/scheme/acpi.rs b/src/scheme/acpi.rs index eded6a6951..97cf9a9962 100644 --- a/src/scheme/acpi.rs +++ b/src/scheme/acpi.rs @@ -78,7 +78,7 @@ pub fn register_kstop() -> bool { } impl AcpiScheme { - pub fn new(id: SchemeId) -> Self { + pub fn init(id: SchemeId) { // NOTE: This __must__ be called from the main kernel context, while initializing all // schemes. If it is called by any other context, then all ACPI data will probably not even // be mapped. @@ -109,8 +109,6 @@ impl AcpiScheme { if !data_init || !id_init { log::error!("AcpiScheme::init called multiple times"); } - - Self } } diff --git a/src/scheme/debug.rs b/src/scheme/debug.rs index f849400969..5ce328330b 100644 --- a/src/scheme/debug.rs +++ b/src/scheme/debug.rs @@ -42,9 +42,8 @@ pub fn debug_notify() { pub struct DebugScheme; impl DebugScheme { - pub fn new(scheme_id: SchemeId) -> Self { + pub fn init(scheme_id: SchemeId) { SCHEME_ID.call_once(|| scheme_id); - Self } } diff --git a/src/scheme/mod.rs b/src/scheme/mod.rs index 5d690b1653..0507877d6f 100644 --- a/src/scheme/mod.rs +++ b/src/scheme/mod.rs @@ -38,7 +38,7 @@ use self::root::RootScheme; use self::serio::SerioScheme; use self::sys::SysScheme; use self::time::TimeScheme; -use self::user::UserInner; +use self::user::{UserInner, UserScheme}; /// When compiled with the "acpi" feature - `acpi:` - allows drivers to read a limited set of ACPI tables. #[cfg(all(feature = "acpi", any(target_arch = "x86", target_arch = "x86_64")))] @@ -108,7 +108,7 @@ impl<'a> Iterator for SchemeIter<'a> { /// Scheme list type pub struct SchemeList { - map: BTreeMap>, + map: BTreeMap, names: BTreeMap, SchemeId>>, next_ns: usize, next_id: usize @@ -136,9 +136,12 @@ impl SchemeList { //TODO: Only memory: is in the null namespace right now. It should be removed when //anonymous mmap's are implemented - self.insert(ns, "memory", |_| Arc::new(MemoryScheme::new())).unwrap(); - self.insert(ns, "thisproc", |_| Arc::new(ProcScheme::restricted())).unwrap(); - self.insert(ns, "pipe", |scheme_id| PipeScheme::new(scheme_id)).unwrap(); + self.insert(ns, "memory", |_| KernelSchemes::Memory).unwrap(); + self.insert(ns, "thisproc", |_| KernelSchemes::Proc(Arc::new(ProcScheme::restricted()))).unwrap(); + self.insert(ns, "pipe", |scheme_id| { + PipeScheme::init(scheme_id); + KernelSchemes::Pipe + }).unwrap(); } /// Initialize a new namespace @@ -147,13 +150,16 @@ impl SchemeList { self.next_ns += 1; self.names.insert(ns, BTreeMap::new()); - self.insert(ns, "", |scheme_id| Arc::new(RootScheme::new(ns, scheme_id))).unwrap(); - self.insert(ns, "event", |_| Arc::new(EventScheme)).unwrap(); - self.insert(ns, "itimer", |_| Arc::new(ITimerScheme::new())).unwrap(); - self.insert(ns, "memory", |_| Arc::new(MemoryScheme::new())).unwrap(); - self.insert(ns, "pipe", |scheme_id| PipeScheme::new(scheme_id)).unwrap(); - self.insert(ns, "sys", |_| Arc::new(SysScheme::new())).unwrap(); - self.insert(ns, "time", |scheme_id| Arc::new(TimeScheme::new(scheme_id))).unwrap(); + self.insert(ns, "", |scheme_id| KernelSchemes::Root(Arc::new(RootScheme::new(ns, scheme_id)))).unwrap(); + self.insert(ns, "event", |_| KernelSchemes::Event).unwrap(); + self.insert(ns, "itimer", |_| KernelSchemes::ITimer(Arc::new(ITimerScheme::new()))).unwrap(); + self.insert(ns, "memory", |_| KernelSchemes::Memory).unwrap(); + self.insert(ns, "pipe", |scheme_id| { + PipeScheme::init(scheme_id); + KernelSchemes::Pipe + }).unwrap(); + self.insert(ns, "sys", |_| KernelSchemes::Sys(Arc::new(SysScheme::new()))).unwrap(); + self.insert(ns, "time", |scheme_id| KernelSchemes::Time(Arc::new(TimeScheme::new(scheme_id)))).unwrap(); ns } @@ -164,17 +170,28 @@ impl SchemeList { let ns = self.new_ns(); // These schemes should only be available on the root - #[cfg(all(feature = "acpi", any(target_arch = "x86", target_arch = "x86_64")))] { - self.insert(ns, "kernel.acpi", |scheme_id| Arc::new(AcpiScheme::new(scheme_id))).unwrap(); - } - #[cfg(all(any(target_arch = "aarch64")))] { + #[cfg(all(feature = "acpi", any(target_arch = "x86", target_arch = "x86_64")))] + self.insert(ns, "kernel.acpi", |scheme_id| { + AcpiScheme::init(scheme_id); + KernelSchemes::Acpi + }).unwrap(); + + #[cfg(all(any(target_arch = "aarch64")))] + { self.insert(ns, "kernel.dtb", |scheme_id| Arc::new(DtbScheme::new(scheme_id))).unwrap(); } - self.insert(ns, "debug", |scheme_id| Arc::new(DebugScheme::new(scheme_id))).unwrap(); - self.insert(ns, "irq", |scheme_id| Arc::new(IrqScheme::new(scheme_id))).unwrap(); - self.insert(ns, "proc", |scheme_id| Arc::new(ProcScheme::new(scheme_id))).unwrap(); - self.insert(ns, "thisproc", |_| Arc::new(ProcScheme::restricted())).unwrap(); - self.insert(ns, "serio", |scheme_id| Arc::new(SerioScheme::new(scheme_id))).unwrap(); + + self.insert(ns, "debug", |scheme_id| { + DebugScheme::init(scheme_id); + KernelSchemes::Debug + }).unwrap(); + self.insert(ns, "irq", |scheme_id| KernelSchemes::Irq(Arc::new(IrqScheme::new(scheme_id)))).unwrap(); + self.insert(ns, "proc", |scheme_id| KernelSchemes::Proc(Arc::new(ProcScheme::new(scheme_id)))).unwrap(); + self.insert(ns, "thisproc", |_| KernelSchemes::Proc(Arc::new(ProcScheme::restricted()))).unwrap(); + self.insert(ns, "serio", |scheme_id| { + SerioScheme::init(scheme_id); + KernelSchemes::Serio + }).unwrap(); } pub fn make_ns(&mut self, from: SchemeNamespace, names: impl IntoIterator>) -> Result { @@ -206,11 +223,11 @@ impl SchemeList { } /// Get the nth scheme. - pub fn get(&self, id: SchemeId) -> Option<&Arc> { + pub fn get(&self, id: SchemeId) -> Option<&KernelSchemes> { self.map.get(&id) } - pub fn get_name(&self, ns: SchemeNamespace, name: &str) -> Option<(SchemeId, &Arc)> { + pub fn get_name(&self, ns: SchemeNamespace, name: &str) -> Option<(SchemeId, &KernelSchemes)> { if let Some(names) = self.names.get(&ns) { if let Some(&id) = names.get(name) { return self.get(id).map(|scheme| (id, scheme)); @@ -220,11 +237,11 @@ impl SchemeList { } /// Create a new scheme. - pub fn insert(&mut self, ns: SchemeNamespace, name: &str, scheme_fn: impl FnOnce(SchemeId) -> Arc) -> Result { + pub fn insert(&mut self, ns: SchemeNamespace, name: &str, scheme_fn: impl FnOnce(SchemeId) -> KernelSchemes) -> Result { self.insert_and_pass(ns, name, |id| (scheme_fn(id), ())).map(|(id, ())| id) } - pub fn insert_and_pass(&mut self, ns: SchemeNamespace, name: &str, scheme_fn: impl FnOnce(SchemeId) -> (Arc, T)) -> Result<(SchemeId, T)> { + pub fn insert_and_pass(&mut self, ns: SchemeNamespace, name: &str, scheme_fn: impl FnOnce(SchemeId) -> (KernelSchemes, T)) -> Result<(SchemeId, T)> { if let Some(names) = self.names.get(&ns) { if names.contains_key(name) { return Err(Error::new(EEXIST)); @@ -402,3 +419,46 @@ pub fn calc_seek_offset(cur_pos: usize, rel_pos: isize, whence: usize, len: usiz _ => return Err(Error::new(EINVAL)), } } + +#[derive(Clone)] +pub enum KernelSchemes { + Debug, + Event, + Irq(Arc), + ITimer(Arc), + Memory, + Pipe, + Proc(Arc), + Root(Arc), + Serio, + Sys(Arc), + Time(Arc), + User(UserScheme), + + #[cfg(all(feature = "acpi", any(target_arch = "x86", target_arch = "x86_64")))] + Acpi, +} + +impl core::ops::Deref for KernelSchemes { + type Target = dyn KernelScheme; + + fn deref(&self) -> &Self::Target { + match self { + Self::Debug => &DebugScheme, + Self::Event => &EventScheme, + Self::Irq(scheme) => &**scheme, + Self::ITimer(scheme) => &**scheme, + Self::Memory => &MemoryScheme, + Self::Pipe => &PipeScheme, + Self::Proc(scheme) => &**scheme, + Self::Root(scheme) => &**scheme, + Self::Serio => &SerioScheme, + Self::Sys(scheme) => &**scheme, + Self::Time(scheme) => &**scheme, + Self::User(scheme) => scheme, + + #[cfg(all(feature = "acpi", any(target_arch = "x86", target_arch = "x86_64")))] + Self::Acpi => &AcpiScheme, + } + } +} diff --git a/src/scheme/pipe.rs b/src/scheme/pipe.rs index 5cd1503ba3..bc5f99da52 100644 --- a/src/scheme/pipe.rs +++ b/src/scheme/pipe.rs @@ -17,14 +17,14 @@ use super::{KernelScheme, OpenResult, CallerCtx}; // TODO: Preallocate a number of scheme IDs, since there can only be *one* root namespace, and // therefore only *one* pipe scheme. -static THE_PIPE_SCHEME: Once<(SchemeId, Arc)> = Once::new(); +static SCHEME_ID: Once = Once::new(); static PIPE_NEXT_ID: AtomicUsize = AtomicUsize::new(1); // TODO: SLOB? static PIPES: RwLock>> = RwLock::new(BTreeMap::new()); pub fn pipe_scheme_id() -> SchemeId { - THE_PIPE_SCHEME.get().expect("pipe scheme must be initialized").0 + *SCHEME_ID.get().expect("pipe scheme must be initialized") } const MAX_QUEUE_SIZE: usize = 65536; @@ -57,10 +57,8 @@ pub fn pipe(flags: usize) -> Result<(usize, usize)> { pub struct PipeScheme; impl PipeScheme { - pub fn new(scheme_id: SchemeId) -> Arc { - Arc::clone(&THE_PIPE_SCHEME.call_once(|| { - (scheme_id, Arc::new(Self)) - }).1) + pub fn init(scheme_id: SchemeId) { + SCHEME_ID.call_once(|| scheme_id); } } diff --git a/src/scheme/proc.rs b/src/scheme/proc.rs index 6183b87b06..a60064bf3d 100644 --- a/src/scheme/proc.rs +++ b/src/scheme/proc.rs @@ -30,7 +30,7 @@ use core::{ }; use spin::{Once, RwLock}; -use super::{OpenResult, CallerCtx}; +use super::{OpenResult, CallerCtx, KernelSchemes}; fn read_from(dst: UserSliceWo, src: &[u8], offset: &mut usize) -> Result { let avail_src = src.get(*offset..).unwrap_or(&[]); @@ -1248,11 +1248,11 @@ fn inherit_context() -> Result { Ok(new_id) } -fn extract_scheme_number(fd: usize) -> Result<(Arc, usize)> { +fn extract_scheme_number(fd: usize) -> Result<(KernelSchemes, usize)> { let (scheme_id, number) = match &*context::contexts().current().ok_or(Error::new(ESRCH))?.read().get_file(FileHandle::from(fd)).ok_or(Error::new(EBADF))?.description.read() { desc => (desc.scheme, desc.number) }; - let scheme = Arc::clone(scheme::schemes().get(scheme_id).ok_or(Error::new(ENODEV))?); + let scheme = scheme::schemes().get(scheme_id).ok_or(Error::new(ENODEV))?.clone(); Ok((scheme, number)) } diff --git a/src/scheme/root.rs b/src/scheme/root.rs index 4bdbb6b910..58197dd1fc 100644 --- a/src/scheme/root.rs +++ b/src/scheme/root.rs @@ -17,7 +17,7 @@ use crate::scheme::{self, SchemeNamespace, SchemeId}; use crate::scheme::user::{UserInner, UserScheme}; use crate::syscall::usercopy::{UserSliceWo, UserSliceRo}; -use super::{KernelScheme, CallerCtx, OpenResult, calc_seek_offset}; +use super::{KernelScheme, KernelSchemes, CallerCtx, OpenResult, calc_seek_offset}; struct FolderInner { data: Box<[u8]>, @@ -96,7 +96,7 @@ impl KernelScheme for RootScheme { let (_scheme_id, inner) = schemes.insert_and_pass(self.scheme_ns, path, |scheme_id| { let inner = Arc::new(UserInner::new(self.scheme_id, scheme_id, id, path_box, flags, context)); - (Arc::new(UserScheme::new(Arc::downgrade(&inner))), inner) + (KernelSchemes::User(UserScheme::new(Arc::downgrade(&inner))), inner) })?; inner diff --git a/src/scheme/serio.rs b/src/scheme/serio.rs index 1335d5dca5..70e9fd747a 100644 --- a/src/scheme/serio.rs +++ b/src/scheme/serio.rs @@ -42,9 +42,8 @@ pub fn serio_input(index: usize, data: u8) { pub struct SerioScheme; impl SerioScheme { - pub fn new(scheme_id: SchemeId) -> Self { + pub fn init(scheme_id: SchemeId) { SCHEME_ID.call_once(|| scheme_id); - Self } } diff --git a/src/scheme/user.rs b/src/scheme/user.rs index 80ebdb8dbc..b2aa97ec48 100644 --- a/src/scheme/user.rs +++ b/src/scheme/user.rs @@ -750,6 +750,7 @@ fn page_range_containing(base: usize, size: usize) -> (Page, usize, usize) { } /// `UserInner` has to be wrapped +#[derive(Clone)] pub struct UserScheme { inner: Weak } diff --git a/src/syscall/fs.rs b/src/syscall/fs.rs index 0e0554e60c..255d07417c 100644 --- a/src/syscall/fs.rs +++ b/src/syscall/fs.rs @@ -23,7 +23,7 @@ pub fn file_op_generic_ext(fd: FileHandle, op: impl FnOnce(&dyn KernelScheme, }; let FileDescription { scheme: scheme_id, number, .. } = *file.description.read(); - let scheme = Arc::clone(scheme::schemes().get(scheme_id).ok_or(Error::new(EBADF))?); + let scheme = scheme::schemes().get(scheme_id).ok_or(Error::new(EBADF))?.clone(); op(&*scheme, scheme_id, &ctx, number) } @@ -64,7 +64,7 @@ pub fn open(raw_path: UserSliceRo, flags: usize) -> Result { let (scheme_id, scheme) = { let schemes = scheme::schemes(); let (scheme_id, scheme) = schemes.get_name(scheme_ns, scheme_name).ok_or(Error::new(ENODEV))?; - (scheme_id, Arc::clone(scheme)) + (scheme_id, scheme.clone()) }; match scheme.kopen(reference, flags, CallerCtx { uid, gid, pid })? { @@ -104,7 +104,7 @@ pub fn rmdir(raw_path: UserSliceRo) -> Result<()> { let scheme = { let schemes = scheme::schemes(); let (_scheme_id, scheme) = schemes.get_name(scheme_ns, scheme_name).ok_or(Error::new(ENODEV))?; - Arc::clone(scheme) + scheme.clone() }; scheme.rmdir(reference, caller_ctx) } @@ -127,7 +127,7 @@ pub fn unlink(raw_path: UserSliceRo) -> Result<()> { let scheme = { let schemes = scheme::schemes(); let (_scheme_id, scheme) = schemes.get_name(scheme_ns, scheme_name).ok_or(Error::new(ENODEV))?; - Arc::clone(scheme) + scheme.clone() }; scheme.unlink(reference, caller_ctx) } @@ -158,11 +158,9 @@ fn duplicate_file(fd: FileHandle, user_buf: UserSliceRo) -> Result Arc::new(RwLock::new(FileDescription { @@ -250,11 +248,10 @@ pub fn fcntl(fd: FileHandle, cmd: usize, arg: usize) -> Result { // Communicate fcntl with scheme if cmd != F_DUPFD && cmd != F_GETFD && cmd != F_SETFD { - let scheme = { - let schemes = scheme::schemes(); - let scheme = schemes.get(description.scheme).ok_or(Error::new(EBADF))?; - Arc::clone(scheme) - }; + let scheme = scheme::schemes() + .get(description.scheme).ok_or(Error::new(EBADF))? + .clone(); + scheme.fcntl(description.number, cmd, arg)?; };