diff --git a/Cargo.lock b/Cargo.lock index 7f304690ff..d024866c9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,7 +52,6 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-scheme 0.3.0", "redox_event", "redox_syscall", ] @@ -180,7 +179,6 @@ dependencies = [ "fdt 0.2.0-alpha1", "libredox", "redox-daemon", - "redox-scheme 0.3.0", "redox_event", "redox_syscall", ] @@ -392,7 +390,9 @@ checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" name = "driver-block" version = "0.1.0" dependencies = [ + "libredox", "partitionlib", + "redox-scheme 0.3.0", "redox_syscall", ] @@ -680,7 +680,6 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-scheme 0.3.0", "redox_event", "redox_syscall", ] @@ -781,9 +780,9 @@ name = "lived" version = "0.1.0" dependencies = [ "anyhow", + "driver-block", "libredox", "redox-daemon", - "redox-scheme 0.3.0", "redox_event", "redox_syscall", ] @@ -856,7 +855,6 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-scheme 0.3.0", "redox_event", "redox_syscall", "smallvec 1.13.2", @@ -1673,7 +1671,7 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-scheme 0.3.0", + "redox_event", "redox_syscall", "spin", "static_assertions", diff --git a/net/driver-network/src/lib.rs b/net/driver-network/src/lib.rs index 0f5a8663a9..d811464b70 100644 --- a/net/driver-network/src/lib.rs +++ b/net/driver-network/src/lib.rs @@ -72,13 +72,13 @@ impl NetworkScheme { &mut self.adapter } - /// Process pending and new packets. + /// Process pending and new requests. /// /// This needs to be called each time there is a new event on the scheme /// file and each time a new network packet has been received by the /// driver. // FIXME maybe split into one method for events on the scheme fd and one - // to call when an irq is received to indicate that blocked packets can + // to call when an irq is received to indicate that blocked requests can // be processed. pub fn tick(&mut self) -> io::Result<()> { // Handle any blocked requests diff --git a/storage/ahcid/Cargo.toml b/storage/ahcid/Cargo.toml index 5186da6460..7b1a06accf 100644 --- a/storage/ahcid/Cargo.toml +++ b/storage/ahcid/Cargo.toml @@ -14,5 +14,4 @@ common = { path = "../../common" } driver-block = { path = "../driver-block" } pcid = { path = "../../pcid" } libredox = "0.1.3" -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } redox_event = "0.4" diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index 1c5239c1b5..9ea8964dd1 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -7,18 +7,14 @@ use std::io::{Read, Write}; use std::os::fd::AsRawFd; use std::usize; +use common::io::Io; +use driver_block::DiskScheme; use event::{EventFlags, RawEventQueue}; use pcid_interface::PciFunctionHandle; -use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; -use syscall::error::{Error, ENODEV}; use log::{error, info}; -use syscall::{EAGAIN, EWOULDBLOCK}; - -use crate::scheme::DiskScheme; pub mod ahci; -pub mod scheme; fn main() { redox_daemon::Daemon::new(daemon).expect("ahcid: failed to daemonize"); @@ -48,18 +44,27 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let address = unsafe { pcid_handle.map_bar(5) }.ptr.as_ptr() as usize; { + let (hba_mem, disks) = ahci::disks(address as usize, &name); + let scheme_name = format!("disk.{}", name); - let socket = Socket::nonblock(&scheme_name).expect("ahcid: failed to create disk scheme"); + let mut scheme = DiskScheme::new( + scheme_name, + disks + .into_iter() + .enumerate() + .map(|(i, disk)| (i as u32, disk)) + .collect(), + ); let mut irq_file = irq.irq_handle("ahcid"); let irq_fd = irq_file.as_raw_fd() as usize; - let mut event_queue = RawEventQueue::new().expect("ahcid: failed to create event queue"); + let event_queue = RawEventQueue::new().expect("ahcid: failed to create event queue"); libredox::call::setrens(0, 0).expect("ahcid: failed to enter null namespace"); event_queue - .subscribe(socket.inner().raw(), 1, EventFlags::READ) + .subscribe(scheme.event_handle().raw(), 1, EventFlags::READ) .expect("ahcid: failed to event scheme socket"); event_queue .subscribe(irq_fd, 1, EventFlags::READ) @@ -67,52 +72,10 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { daemon.ready().expect("ahcid: failed to notify parent"); - let (hba_mem, disks) = ahci::disks(address as usize, &name); - let mut scheme = DiskScheme::new(scheme_name, hba_mem, disks); - - let mut mounted = true; - let mut todo = Vec::new(); - while mounted { - let Some(event) = event_queue - .next() - .transpose() - .expect("ahcid: failed to read event file") - else { - break; - }; - if event.fd == socket.inner().raw() { - loop { - let sqe = match socket.next_request(SignalBehavior::Interrupt) { - Ok(None) => { - mounted = false; - break; - } - Ok(Some(s)) => { - if let RequestKind::Call(call) = s.kind() { - call - } else { - // TODO: Support e.g. cancellation - continue; - } - } - Err(err) => { - if err.errno == EWOULDBLOCK || err.errno == EAGAIN { - break; - } else { - panic!("ahcid: failed to read disk scheme: {}", err); - } - } - }; - - if let Some(response) = sqe.handle_scheme_block(&mut scheme) { - // TODO: handle full CQE? - socket - .write_response(response, SignalBehavior::Restart) - .expect("ahcid: failed to write disk scheme"); - } else { - todo.push(sqe); - } - } + for event in event_queue { + let event = event.unwrap(); + if event.fd == scheme.event_handle().raw() { + scheme.tick().unwrap(); } else if event.fd == irq_fd { let mut irq = [0; 8]; if irq_file @@ -120,52 +83,29 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .expect("ahcid: failed to read irq file") >= irq.len() { - if scheme.irq() { + let is = hba_mem.is.read(); + if is > 0 { + let pi = hba_mem.pi.read(); + let pi_is = pi & is; + for i in 0..hba_mem.ports.len() { + if pi_is & 1 << i > 0 { + let port = &mut hba_mem.ports[i]; + let is = port.is.read(); + port.is.write(is); + } + } + hba_mem.is.write(is); + irq_file .write(&irq) .expect("ahcid: failed to write irq file"); - // Handle todos in order to finish previous packets if possible - let mut i = 0; - while i < todo.len() { - if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { - let _sqe = todo.remove(i); - socket - .write_response(resp, SignalBehavior::Restart) - .expect("ahcid: failed to write disk scheme"); - } else { - i += 1; - } - } + scheme.tick().unwrap(); } } } else { error!("Unknown event {}", event.fd); } - - // Handle todos to start new packets if possible - let mut i = 0; - while i < todo.len() { - if let Some(response) = todo[i].handle_scheme_block(&mut scheme) { - let _sqe = todo.remove(i); - socket - .write_response(response, SignalBehavior::Restart) - .expect("ahcid: failed to write disk scheme"); - } else { - i += 1; - } - } - - if !mounted { - for sqe in todo.drain(..) { - socket - .write_response( - Response::new(&sqe, Err(Error::new(ENODEV))), - SignalBehavior::Restart, - ) - .expect("ahcid: failed to write disk scheme"); - } - } } } diff --git a/storage/ahcid/src/scheme.rs b/storage/ahcid/src/scheme.rs deleted file mode 100644 index 74dc53067e..0000000000 --- a/storage/ahcid/src/scheme.rs +++ /dev/null @@ -1,329 +0,0 @@ -use std::collections::BTreeMap; -use std::fmt::Write; -use std::str; - -use common::io::Io as _; -use driver_block::{Disk, DiskWrapper}; -use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; -use syscall::schemev2::NewFdFlags; -use syscall::{ - Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, MODE_DIR, MODE_FILE, O_DIRECTORY, - O_STAT, -}; - -use crate::ahci::hba::HbaMem; - -enum Handle { - List(Vec), // Dir contents buffer - Disk(usize), // Disk index - Partition(usize, u32), // Disk index, partition index -} - -pub struct DiskScheme { - scheme_name: String, - hba_mem: &'static mut HbaMem, - disks: Box<[DiskWrapper>]>, - handles: BTreeMap, - next_id: usize, -} - -impl DiskScheme { - pub fn new( - scheme_name: String, - hba_mem: &'static mut HbaMem, - disks: Vec>, - ) -> DiskScheme { - DiskScheme { - scheme_name, - hba_mem, - disks: disks - .into_iter() - .map(DiskWrapper::new) - .collect::>() - .into_boxed_slice(), - handles: BTreeMap::new(), - next_id: 0, - } - } - - pub fn irq(&mut self) -> bool { - let is = self.hba_mem.is.read(); - if is > 0 { - let pi = self.hba_mem.pi.read(); - let pi_is = pi & is; - for i in 0..self.hba_mem.ports.len() { - if pi_is & 1 << i > 0 { - let port = &mut self.hba_mem.ports[i]; - let is = port.is.read(); - port.is.write(is); - } - } - self.hba_mem.is.write(is); - true - } else { - false - } - } - - // Checks if any conflicting handles already exist - fn check_locks(&self, disk_i: usize, part_i_opt: Option) -> Result<()> { - for (_, handle) in self.handles.iter() { - match handle { - Handle::Disk(i) => { - if disk_i == *i { - return Err(Error::new(ENOLCK)); - } - } - Handle::Partition(i, p) => { - if disk_i == *i { - match part_i_opt { - Some(part_i) => { - if part_i == *p { - return Err(Error::new(ENOLCK)); - } - } - None => { - return Err(Error::new(ENOLCK)); - } - } - } - } - _ => (), - } - } - Ok(()) - } -} - -impl SchemeBlock for DiskScheme { - fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result> { - if ctx.uid != 0 { - return Err(Error::new(EACCES)); - } - let path_str = path.trim_matches('/'); - - let handle = if path_str.is_empty() { - if flags & O_DIRECTORY != O_DIRECTORY && flags & O_STAT != O_STAT { - return Err(Error::new(EISDIR)); - } - let mut list = String::new(); - - for (disk_index, disk) in self.disks.iter().enumerate() { - write!(list, "{}\n", disk_index).unwrap(); - - if disk.pt.is_none() { - continue; - } - for part_index in 0..disk.pt.as_ref().unwrap().partitions.len() { - write!(list, "{}p{}\n", disk_index, part_index).unwrap(); - } - } - - Handle::List(list.into_bytes()) - } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { - let disk_id_str = &path_str[..p_pos]; - if p_pos + 1 >= path_str.len() { - return Err(Error::new(ENOENT)); - } - let part_id_str = &path_str[p_pos + 1..]; - let i = disk_id_str.parse::().or(Err(Error::new(ENOENT)))?; - let p = part_id_str.parse::().or(Err(Error::new(ENOENT)))?; - - let disk = self.disks.get(i).ok_or(Error::new(ENOENT))?; - if disk.pt.is_none() - || disk - .pt - .as_ref() - .unwrap() - .partitions - .get(p as usize) - .is_none() - { - return Err(Error::new(ENOENT)); - } - - self.check_locks(i, Some(p))?; - - Handle::Partition(i, p) - } else { - let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; - - if self.disks.get(i).is_none() { - return Err(Error::new(ENOENT)); - } - self.check_locks(i, None)?; - - Handle::Disk(i) - }; - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, handle); - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } - - fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { - match *self.handles.get(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref data) => { - stat.st_mode = MODE_DIR; - stat.st_size = data.len() as u64; - Ok(Some(0)) - } - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - stat.st_mode = MODE_FILE; - stat.st_size = disk.size(); - stat.st_blksize = disk.block_size(); - Ok(Some(0)) - } - Handle::Partition(disk_id, part_num) => { - let disk = self.disks.get_mut(disk_id).ok_or(Error::new(EBADF))?; - let size = { - let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; - partition.size - }; - - stat.st_mode = MODE_FILE; // TODO: Block device? - stat.st_size = size * u64::from(disk.block_size()); - stat.st_blksize = disk.block_size(); - stat.st_blocks = size; - Ok(Some(0)) - } - } - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - let mut i = 0; - - let scheme_name = self.scheme_name.as_bytes(); - let mut j = 0; - while i < buf.len() && j < scheme_name.len() { - buf[i] = scheme_name[j]; - i += 1; - j += 1; - } - - if i < buf.len() { - buf[i] = b':'; - i += 1; - } - - match *handle { - Handle::List(_) => (), - Handle::Disk(number) => { - let number_str = format!("{}", number); - let number_bytes = number_str.as_bytes(); - j = 0; - while i < buf.len() && j < number_bytes.len() { - buf[i] = number_bytes[j]; - i += 1; - j += 1; - } - } - Handle::Partition(disk_num, part_num) => { - let path = format!("{}p{}", disk_num, part_num); - let path_bytes = path.as_bytes(); - j = 0; - while i < buf.len() && j < path_bytes.len() { - buf[i] = path_bytes[j]; - i += 1; - j += 1; - } - } - } - - Ok(Some(i)) - } - - fn read( - &mut self, - id: usize, - buf: &mut [u8], - offset: u64, - _fcntl_flags: u32, - ) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref handle) => { - let src = usize::try_from(offset) - .ok() - .and_then(|o| handle.get(o..)) - .unwrap_or(&[]); - - let byte_count = core::cmp::min(src.len(), buf.len()); - buf[..byte_count].copy_from_slice(&src[..byte_count]); - Ok(Some(byte_count)) - } - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.read(None, block, buf) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.read(Some(part_num as usize), block, buf) - } - } - } - - fn write( - &mut self, - id: usize, - buf: &[u8], - offset: u64, - _fcntl_flags: u32, - ) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(_) => Err(Error::new(EBADF)), - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.write(None, block, buf) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.write(Some(part_num as usize), block, buf) - } - } - } - - fn fsize(&mut self, id: usize) -> Result> { - Ok(Some( - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref mut handle) => handle.len() as u64, - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - disk.size() - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block_count = disk - .pt - .as_ref() - .ok_or(Error::new(EBADF))? - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))? - .size; - u64::from(disk.block_size()) * block_count - } - }, - )) - } - - fn close(&mut self, id: usize) -> Result> { - self.handles - .remove(&id) - .ok_or(Error::new(EBADF)) - .and(Ok(Some(0))) - } -} diff --git a/storage/bcm2835-sdhcid/Cargo.toml b/storage/bcm2835-sdhcid/Cargo.toml index ac42319149..ceabb4a0b6 100644 --- a/storage/bcm2835-sdhcid/Cargo.toml +++ b/storage/bcm2835-sdhcid/Cargo.toml @@ -13,5 +13,4 @@ driver-block = { path = "../driver-block" } redox-daemon = "0.1" libredox = "0.1.3" redox_syscall = { version = "0.5", features = ["std"] } -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } redox_event = "0.4" diff --git a/storage/bcm2835-sdhcid/src/main.rs b/storage/bcm2835-sdhcid/src/main.rs index fded57eb4b..34668a55f9 100644 --- a/storage/bcm2835-sdhcid/src/main.rs +++ b/storage/bcm2835-sdhcid/src/main.rs @@ -1,27 +1,11 @@ #![feature(let_chains)] -use std::{ - fs::File, - io::{Read, Write}, - process, -}; +use std::process; -use driver_block::Disk; +use driver_block::{Disk, DiskScheme}; use event::{EventFlags, RawEventQueue}; -use fdt::{node::FdtNode, Fdt}; -use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; -use syscall::{ - data::{Event, Packet}, - error::{Error, ENODEV}, - flag::EVENT_READ, - io::Io, - scheme::SchemeBlockMut, - EAGAIN, EINTR, EWOULDBLOCK, -}; +use fdt::Fdt; -use crate::scheme::DiskScheme; - -mod scheme; mod sd; #[cfg(target_os = "redox")] @@ -114,82 +98,32 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { */ } - let scheme_name = "disk.mmc"; - let socket_fd = Socket::create(&scheme_name).expect("mmcd: failed to create disk scheme"); + let mut disks = Vec::new(); + disks.push(Box::new(sdhci) as Box); + let mut scheme = DiskScheme::new( + "disk.mmc".to_string(), + disks + .into_iter() + .enumerate() + .map(|(i, disk)| (i as u32, disk)) + .collect(), + ); - let mut event_queue = RawEventQueue::new().expect("mmcd: failed to open event file"); + let event_queue = RawEventQueue::new().expect("mmcd: failed to open event file"); event_queue - .subscribe(socket_fd.inner().raw(), 0, EventFlags::READ) + .subscribe(scheme.event_handle().raw(), 0, EventFlags::READ) .expect("mmcd: failed to event disk scheme"); libredox::call::setrens(0, 0).expect("mmcd: failed to enter null namespace"); daemon.ready().expect("mmcd: failed to notify parent"); - let mut todo = Vec::new(); - let mut disks = Vec::new(); - - disks.push(Box::new(sdhci) as Box); - let mut scheme = DiskScheme::new(scheme_name.to_string(), disks); - - 'outer: loop { - let Some(event) = event_queue - .next() - .transpose() - .expect("mmcd: failed to read event file") - else { - break; - }; - if event.fd == socket_fd.inner().raw() { - loop { - let req = match socket_fd.next_request(SignalBehavior::Interrupt) { - Ok(None) => break 'outer, - Ok(Some(r)) => { - if let RequestKind::Call(c) = r.kind() { - c - } else { - continue; - } - } - Err(err) => { - if matches!(err.errno, EAGAIN | EWOULDBLOCK | EINTR) { - break; - } else { - panic!("mmcd: failed to read disk scheme: {}", err); - } - } - }; - if let Some(resp) = req.handle_scheme_block(&mut scheme) { - socket_fd - .write_response(resp, SignalBehavior::Restart) - .expect("mmcd: failed to write disk scheme"); - } else { - todo.push(req); - } - } + for event in event_queue { + let event = event.unwrap(); + if event.fd == scheme.event_handle().raw() { + scheme.tick().unwrap(); } else { println!("Unknown event {}", event.fd); } - - // Handle todos to start new packets if possible - let mut i = 0; - while i < todo.len() { - if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { - socket_fd - .write_response(resp, SignalBehavior::Restart) - .expect("mmcd: failed to write disk scheme"); - } else { - i += 1; - } - } - - for req in todo.drain(..) { - socket_fd - .write_response( - Response::new(&req, Err(Error::new(ENODEV))), - SignalBehavior::Restart, - ) - .expect("mmcd: failed to write disk scheme"); - } } process::exit(0); } diff --git a/storage/bcm2835-sdhcid/src/scheme.rs b/storage/bcm2835-sdhcid/src/scheme.rs deleted file mode 100644 index dfd7264786..0000000000 --- a/storage/bcm2835-sdhcid/src/scheme.rs +++ /dev/null @@ -1,309 +0,0 @@ -use std::collections::BTreeMap; -use std::fmt::Write; -use std::str; - -use driver_block::{Disk, DiskWrapper}; -use syscall::schemev2::NewFdFlags; -use syscall::{ - Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, MODE_DIR, MODE_FILE, O_DIRECTORY, - O_STAT, -}; - -use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; - -enum Handle { - List(Vec), // Dir contents buffer - Disk(usize), // Disk index - Partition(usize, u32), // Disk index, partition index -} - -pub struct DiskScheme { - scheme_name: String, - disks: Box<[DiskWrapper>]>, - handles: BTreeMap, - next_id: usize, -} - -impl DiskScheme { - pub fn new(scheme_name: String, disks: Vec>) -> DiskScheme { - DiskScheme { - scheme_name, - disks: disks - .into_iter() - .map(DiskWrapper::new) - .collect::>() - .into_boxed_slice(), - handles: BTreeMap::new(), - next_id: 0, - } - } - - // Checks if any conflicting handles already exist - fn check_locks(&self, disk_i: usize, part_i_opt: Option) -> Result<()> { - for (_, handle) in self.handles.iter() { - match handle { - Handle::Disk(i) => { - if disk_i == *i { - return Err(Error::new(ENOLCK)); - } - } - Handle::Partition(i, p) => { - if disk_i == *i { - match part_i_opt { - Some(part_i) => { - if part_i == *p { - return Err(Error::new(ENOLCK)); - } - } - None => { - return Err(Error::new(ENOLCK)); - } - } - } - } - _ => (), - } - } - Ok(()) - } -} - -impl SchemeBlock for DiskScheme { - fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result> { - if ctx.uid == 0 { - let path_str = path.trim_matches('/'); - if path_str.is_empty() { - if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { - let mut list = String::new(); - - for (disk_index, disk) in self.disks.iter().enumerate() { - write!(list, "{}\n", disk_index).unwrap(); - - if disk.pt.is_none() { - continue; - } - for part_index in 0..disk.pt.as_ref().unwrap().partitions.len() { - write!(list, "{}p{}\n", disk_index, part_index).unwrap(); - } - } - - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle::List(list.into_bytes())); - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } else { - Err(Error::new(EISDIR)) - } - } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { - let disk_id_str = &path_str[..p_pos]; - if p_pos + 1 >= path_str.len() { - return Err(Error::new(ENOENT)); - } - let part_id_str = &path_str[p_pos + 1..]; - let i = disk_id_str.parse::().or(Err(Error::new(ENOENT)))?; - let p = part_id_str.parse::().or(Err(Error::new(ENOENT)))?; - - if let Some(disk) = self.disks.get(i) { - if disk.pt.is_none() - || disk - .pt - .as_ref() - .unwrap() - .partitions - .get(p as usize) - .is_none() - { - return Err(Error::new(ENOENT)); - } - - self.check_locks(i, Some(p))?; - - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle::Partition(i, p)); - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } else { - Err(Error::new(ENOENT)) - } - } else { - let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; - - if self.disks.get(i).is_some() { - self.check_locks(i, None)?; - - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle::Disk(i)); - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } else { - Err(Error::new(ENOENT)) - } - } - } else { - Err(Error::new(EACCES)) - } - } - - fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { - match *self.handles.get(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref data) => { - stat.st_mode = MODE_DIR; - stat.st_size = data.len() as u64; - Ok(Some(0)) - } - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - stat.st_mode = MODE_FILE; - stat.st_size = disk.size(); - stat.st_blksize = disk.block_size(); - Ok(Some(0)) - } - Handle::Partition(disk_id, part_num) => { - let disk = self.disks.get_mut(disk_id).ok_or(Error::new(EBADF))?; - let size = { - let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; - partition.size - }; - - stat.st_mode = MODE_FILE; // TODO: Block device? - stat.st_size = size * u64::from(disk.block_size()); - stat.st_blksize = disk.block_size(); - stat.st_blocks = size; - Ok(Some(0)) - } - } - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - let mut i = 0; - - let scheme_name = self.scheme_name.as_bytes(); - let mut j = 0; - while i < buf.len() && j < scheme_name.len() { - buf[i] = scheme_name[j]; - i += 1; - j += 1; - } - - if i < buf.len() { - buf[i] = b':'; - i += 1; - } - - match *handle { - Handle::List(_) => (), - Handle::Disk(number) => { - let number_str = format!("{}", number); - let number_bytes = number_str.as_bytes(); - j = 0; - while i < buf.len() && j < number_bytes.len() { - buf[i] = number_bytes[j]; - i += 1; - j += 1; - } - } - Handle::Partition(disk_num, part_num) => { - let path = format!("{}p{}", disk_num, part_num); - let path_bytes = path.as_bytes(); - j = 0; - while i < buf.len() && j < path_bytes.len() { - buf[i] = path_bytes[j]; - i += 1; - j += 1; - } - } - } - - Ok(Some(i)) - } - - fn read( - &mut self, - id: usize, - buf: &mut [u8], - offset: u64, - _flags: u32, - ) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref handle) => { - let src = usize::try_from(offset) - .ok() - .and_then(|o| handle.get(o..)) - .unwrap_or(&[]); - let bytes = src.len().min(buf.len()); - buf[..bytes].copy_from_slice(&src[..bytes]); - Ok(Some(bytes)) - } - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.read(None, block, buf) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.read(Some(part_num as usize), block, buf) - } - } - } - - fn write(&mut self, id: usize, buf: &[u8], offset: u64, _flags: u32) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(_) => Err(Error::new(EBADF)), - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.write(None, block, buf) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.write(Some(part_num as usize), block, buf) - } - } - } - - fn fsize(&mut self, id: usize) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref mut handle) => Ok(Some(handle.len() as u64)), - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - Ok(Some(disk.size())) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block_count = disk - .pt - .as_ref() - .ok_or(Error::new(EBADF))? - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))? - .size; - Ok(Some(u64::from(disk.block_size()) * block_count)) - } - } - } - - fn close(&mut self, id: usize) -> Result> { - self.handles - .remove(&id) - .ok_or(Error::new(EBADF)) - .and(Ok(Some(0))) - } -} diff --git a/storage/driver-block/Cargo.toml b/storage/driver-block/Cargo.toml index 278520adca..1645bf0314 100644 --- a/storage/driver-block/Cargo.toml +++ b/storage/driver-block/Cargo.toml @@ -6,4 +6,6 @@ edition = "2021" [dependencies] partitionlib = { path = "../partitionlib" } +libredox = "0.1.3" redox_syscall = "0.5" +redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs index a2910c7b11..fa5b4fb22a 100644 --- a/storage/driver-block/src/lib.rs +++ b/storage/driver-block/src/lib.rs @@ -1,9 +1,21 @@ use std::cmp; -use std::io::Error; use std::io::{self, Read, Seek, SeekFrom}; +use std::collections::BTreeMap; +use std::convert::TryFrom; +use std::fmt::Write; +use std::str; + +use libredox::Fd; use partitionlib::{LogicalBlockSize, PartitionTable}; -use syscall::{EBADF, EOVERFLOW}; +use redox_scheme::{ + CallRequest, CallerCtx, OpenResult, RequestKind, Response, SchemeBlock, SignalBehavior, Socket, +}; +use syscall::schemev2::NewFdFlags; +use syscall::{ + Error, Result, Stat, EACCES, EAGAIN, EBADF, EISDIR, ENOENT, ENOLCK, EOPNOTSUPP, EOVERFLOW, + MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, +}; /// Split the read operation into a series of block reads. /// `read_fn` will be called with a block number to be read, and a buffer to be filled. @@ -13,8 +25,8 @@ fn block_read( offset: u64, blksize: u32, buf: &mut [u8], - mut read_fn: impl FnMut(u64, &mut [u8]) -> Result<(), Error>, -) -> Result { + mut read_fn: impl FnMut(u64, &mut [u8]) -> io::Result<()>, +) -> io::Result { // TODO: Yield sometimes, perhaps after a few blocks or something. if buf.len() == 0 { @@ -57,6 +69,8 @@ pub trait Disk { fn block_size(&self) -> u32; fn size(&self) -> u64; + // These operate on a whole multiple of the block size + // FIXME maybe only operate on a single block worth of data? fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result>; fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result>; } @@ -231,3 +245,370 @@ impl DiskWrapper { } } } + +enum Handle { + List(Vec), // entries + Disk(u32), // disk num + Partition(u32, u32), // disk num, part num +} + +pub struct DiskScheme { + scheme_name: String, + socket: Socket, + disks: BTreeMap>, + handles: BTreeMap, + next_id: usize, + blocked: Vec, +} + +impl DiskScheme { + pub fn new(scheme_name: String, disks: BTreeMap) -> Self { + assert!(scheme_name.starts_with("disk")); + let socket = Socket::nonblock(&scheme_name).expect("failed to create disk scheme"); + + Self { + scheme_name, + socket, + disks: disks + .into_iter() + .map(|(k, disk)| (k, DiskWrapper::new(disk))) + .collect(), + next_id: 0, + handles: BTreeMap::new(), + blocked: vec![], + } + } + + pub fn event_handle(&self) -> &Fd { + self.socket.inner() + } + + /// Process pending and new requests. + /// + /// This needs to be called each time there is a new event on the scheme + /// file and each time a read or write operation has completed. + // FIXME maybe split into one method for events on the scheme fd and one + // to call when an irq is received to indicate that blocked packets can + // be processed. + pub fn tick(&mut self) -> io::Result<()> { + // Handle any blocked requests + let mut i = 0; + while i < self.blocked.len() { + if let Some(resp) = self.blocked[i].handle_scheme_block(self) { + self.socket + .write_response(resp, SignalBehavior::Restart) + .expect("driver-block: failed to write scheme"); + self.blocked.remove(i); + } else { + i += 1; + } + } + + // Handle new scheme requests + loop { + let request = match self.socket.next_request(SignalBehavior::Restart) { + Ok(Some(request)) => request, + Ok(None) => { + // Scheme likely got unmounted + std::process::exit(0); + } + Err(err) if err.errno == EAGAIN => break, + Err(err) => return Err(err.into()), + }; + + match request.kind() { + RequestKind::Call(call_request) => { + if let Some(resp) = call_request.handle_scheme_block(self) { + self.socket.write_response(resp, SignalBehavior::Restart)?; + } else { + self.blocked.push(call_request); + } + } + RequestKind::SendFd(sendfd_request) => { + self.socket.write_response( + Response::for_sendfd(&sendfd_request, Err(syscall::Error::new(EOPNOTSUPP))), + SignalBehavior::Restart, + )?; + } + RequestKind::Cancellation(_cancellation_request) => { + // FIXME implement cancellation + } + RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { + unreachable!() + } + } + } + + Ok(()) + } + + // Checks if any conflicting handles already exist + fn check_locks(&self, disk_i: u32, part_i_opt: Option) -> Result<()> { + for (_, handle) in self.handles.iter() { + match handle { + Handle::Disk(i) => { + if disk_i == *i { + return Err(Error::new(ENOLCK)); + } + } + Handle::Partition(i, p) => { + if disk_i == *i { + match part_i_opt { + Some(part_i) => { + if part_i == *p { + return Err(Error::new(ENOLCK)); + } + } + None => { + return Err(Error::new(ENOLCK)); + } + } + } + } + _ => (), + } + } + Ok(()) + } +} + +impl SchemeBlock for DiskScheme { + fn xopen( + &mut self, + path_str: &str, + flags: usize, + ctx: &CallerCtx, + ) -> Result> { + if ctx.uid != 0 { + return Err(Error::new(EACCES)); + } + let path_str = path_str.trim_matches('/'); + + let handle = if path_str.is_empty() { + if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { + let mut list = String::new(); + + for (nsid, disk) in self.disks.iter() { + write!(list, "{}\n", nsid).unwrap(); + + if disk.pt.is_none() { + continue; + } + for part_num in 0..disk.pt.as_ref().unwrap().partitions.len() { + write!(list, "{}p{}\n", nsid, part_num).unwrap(); + } + } + + Handle::List(list.into_bytes()) + } else { + return Err(Error::new(EISDIR)); + } + } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { + let nsid_str = &path_str[..p_pos]; + + if p_pos + 1 >= path_str.len() { + return Err(Error::new(ENOENT)); + } + let part_num_str = &path_str[p_pos + 1..]; + + let nsid = nsid_str.parse::().or(Err(Error::new(ENOENT)))?; + let part_num = part_num_str.parse::().or(Err(Error::new(ENOENT)))?; + + if let Some(disk) = self.disks.get(&nsid) { + if disk + .pt + .as_ref() + .ok_or(Error::new(ENOENT))? + .partitions + .get(part_num as usize) + .is_some() + { + self.check_locks(nsid, Some(part_num))?; + + Handle::Partition(nsid, part_num) + } else { + return Err(Error::new(ENOENT)); + } + } else { + return Err(Error::new(ENOENT)); + } + } else { + let nsid = path_str.parse::().or(Err(Error::new(ENOENT)))?; + + if self.disks.contains_key(&nsid) { + self.check_locks(nsid, None)?; + Handle::Disk(nsid) + } else { + return Err(Error::new(ENOENT)); + } + }; + let id = self.next_id; + self.next_id += 1; + self.handles.insert(id, handle); + Ok(Some(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::POSITIONED, + })) + } + + fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { + match *self.handles.get(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref data) => { + stat.st_mode = MODE_DIR; + stat.st_size = data.len() as u64; + Ok(Some(0)) + } + Handle::Disk(number) => { + let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; + stat.st_mode = MODE_FILE; + stat.st_blocks = disk.disk().size() / u64::from(disk.block_size()); + stat.st_blksize = disk.block_size(); + stat.st_size = disk.size(); + Ok(Some(0)) + } + Handle::Partition(disk_num, part_num) => { + let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; + let part = disk + .pt + .as_ref() + .ok_or(Error::new(EBADF))? + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))?; + stat.st_mode = MODE_FILE; + stat.st_size = part.size * u64::from(disk.block_size()); + stat.st_blocks = part.size; + stat.st_blksize = disk.block_size(); + Ok(Some(0)) + } + } + } + + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + let mut i = 0; + + let scheme_name = self.scheme_name.as_bytes(); + let mut j = 0; + while i < buf.len() && j < scheme_name.len() { + buf[i] = scheme_name[j]; + i += 1; + j += 1; + } + + if i < buf.len() { + buf[i] = b':'; + i += 1; + } + + match *handle { + Handle::List(_) => (), + Handle::Disk(number) => { + let number_str = format!("{}", number); + let number_bytes = number_str.as_bytes(); + j = 0; + while i < buf.len() && j < number_bytes.len() { + buf[i] = number_bytes[j]; + i += 1; + j += 1; + } + } + Handle::Partition(disk_num, part_num) => { + let number_str = format!("{}p{}", disk_num, part_num); + let number_bytes = number_str.as_bytes(); + j = 0; + while i < buf.len() && j < number_bytes.len() { + buf[i] = number_bytes[j]; + i += 1; + j += 1; + } + } + } + + Ok(Some(i)) + } + + fn read( + &mut self, + id: usize, + buf: &mut [u8], + offset: u64, + _fcntl_flags: u32, + ) -> Result> { + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref handle) => { + let src = usize::try_from(offset) + .ok() + .and_then(|o| handle.get(o..)) + .unwrap_or(&[]); + let count = core::cmp::min(src.len(), buf.len()); + buf[..count].copy_from_slice(&src[..count]); + Ok(Some(count)) + } + Handle::Disk(number) => { + let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; + let block = offset / u64::from(disk.block_size()); + disk.read(None, block, buf) + } + Handle::Partition(disk_num, part_num) => { + let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; + let block = offset / u64::from(disk.block_size()); + disk.read(Some(part_num as usize), block, buf) + } + } + } + + fn write( + &mut self, + id: usize, + buf: &[u8], + offset: u64, + _fcntl_flags: u32, + ) -> Result> { + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(_) => Err(Error::new(EBADF)), + Handle::Disk(number) => { + let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; + let block = offset / u64::from(disk.block_size()); + disk.write(None, block, buf) + } + Handle::Partition(disk_num, part_num) => { + let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; + let block = offset / u64::from(disk.block_size()); + disk.write(Some(part_num as usize), block, buf) + } + } + } + + fn fsize(&mut self, id: usize) -> Result> { + Ok(Some( + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref handle) => handle.len() as u64, + Handle::Disk(number) => { + let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; + disk.size() + } + Handle::Partition(disk_num, part_num) => { + let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; + let part = disk + .pt + .as_ref() + .ok_or(Error::new(EBADF))? + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))?; + + part.size * u64::from(disk.block_size()) + } + }, + )) + } + + fn close(&mut self, id: usize) -> Result> { + self.handles + .remove(&id) + .ok_or(Error::new(EBADF)) + .and(Ok(Some(0))) + } +} diff --git a/storage/ided/Cargo.toml b/storage/ided/Cargo.toml index 3a0f34d5f7..9f6ee66745 100644 --- a/storage/ided/Cargo.toml +++ b/storage/ided/Cargo.toml @@ -11,5 +11,4 @@ log = "0.4" pcid = { path = "../../pcid" } redox-daemon = "0.1" redox_syscall = { version = "0.5", features = ["std"] } -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } redox_event = "0.4" diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index 2bf9c7c3e9..c7dd8f8746 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -1,10 +1,9 @@ use common::io::Io as _; -use driver_block::Disk; +use driver_block::{Disk, DiskScheme}; use event::{EventFlags, RawEventQueue}; use libredox::flag; use log::{error, info}; use pcid_interface::PciFunctionHandle; -use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; use std::{ fs::File, io::{Read, Write}, @@ -13,15 +12,10 @@ use std::{ thread::{self, sleep}, time::Duration, }; -use syscall::error::{Error, EAGAIN, EINTR, ENODEV, EWOULDBLOCK}; -use crate::{ - ide::{AtaCommand, AtaDisk, Channel}, - scheme::DiskScheme, -}; +use crate::ide::{AtaCommand, AtaDisk, Channel}; pub mod ide; -pub mod scheme; fn main() { redox_daemon::Daemon::new(daemon).expect("ided: failed to daemonize"); @@ -193,7 +187,14 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } let scheme_name = format!("disk.{}", name); - let socket_fd = Socket::nonblock(&scheme_name).expect("ided: failed to create disk scheme"); + let mut scheme = DiskScheme::new( + scheme_name, + disks + .into_iter() + .enumerate() + .map(|(i, disk)| (i as u32, disk)) + .collect(), + ); let primary_irq_fd = libredox::call::open( &format!("/scheme/irq/{}", primary_irq), @@ -211,14 +212,14 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .expect("ided: failed to open irq file"); let mut secondary_irq_file = unsafe { File::from_raw_fd(secondary_irq_fd as RawFd) }; - let mut event_queue = RawEventQueue::new().expect("ided: failed to open event file"); + let event_queue = RawEventQueue::new().expect("ided: failed to open event file"); libredox::call::setrens(0, 0).expect("ided: failed to enter null namespace"); daemon.ready().expect("ided: failed to notify parent"); event_queue - .subscribe(socket_fd.inner().raw(), 0, EventFlags::READ) + .subscribe(scheme.event_handle().raw(), 0, EventFlags::READ) .expect("ided: failed to event disk scheme"); event_queue @@ -229,44 +230,10 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .subscribe(secondary_irq_fd, 0, EventFlags::READ) .expect("ided: failed to event irq scheme"); - let mut scheme = DiskScheme::new(scheme_name, chans, disks); - - let mut todo = Vec::new(); - 'outer: loop { - let Some(event) = event_queue - .next() - .transpose() - .expect("ided: failed to read event file") - else { - break; - }; - if event.fd == socket_fd.inner().raw() { - loop { - let req = match socket_fd.next_request(SignalBehavior::Interrupt) { - Ok(None) => break 'outer, - Ok(Some(r)) => { - if let RequestKind::Call(c) = r.kind() { - c - } else { - continue; - } - } - Err(err) => { - if matches!(err.errno, EAGAIN | EWOULDBLOCK | EINTR) { - break; - } else { - panic!("ided: failed to read disk scheme: {}", err); - } - } - }; - if let Some(resp) = req.handle_scheme_block(&mut scheme) { - socket_fd - .write_response(resp, SignalBehavior::Restart) - .expect("ided: failed to write disk scheme"); - } else { - todo.push(req); - } - } + for event in event_queue { + let event = event.unwrap(); + if event.fd == scheme.event_handle().raw() { + scheme.tick().unwrap(); } else if event.fd == primary_irq_fd { let mut irq = [0; 8]; if primary_irq_file @@ -274,23 +241,14 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .expect("ided: failed to read irq file") >= irq.len() { - if scheme.irq(0) { - primary_irq_file - .write(&irq) - .expect("ided: failed to write irq file"); + let _chan = chans[0].lock().unwrap(); + //TODO: check chan for irq - // Handle todos in order to finish previous packets if possible - let mut i = 0; - while i < todo.len() { - if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { - socket_fd - .write_response(resp, SignalBehavior::Restart) - .expect("ided: failed to write disk scheme"); - } else { - i += 1; - } - } - } + primary_irq_file + .write(&irq) + .expect("ided: failed to write irq file"); + + scheme.tick().unwrap(); } } else if event.fd == secondary_irq_fd { let mut irq = [0; 8]; @@ -299,48 +257,18 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .expect("ided: failed to read irq file") >= irq.len() { - if scheme.irq(1) { - secondary_irq_file - .write(&irq) - .expect("ided: failed to write irq file"); + let _chan = chans[1].lock().unwrap(); + //TODO: check chan for irq - // Handle todos in order to finish previous packets if possible - let mut i = 0; - while i < todo.len() { - if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { - socket_fd - .write_response(resp, SignalBehavior::Restart) - .expect("ided: failed to write disk scheme"); - } else { - i += 1; - } - } - } + secondary_irq_file + .write(&irq) + .expect("ided: failed to write irq file"); + + scheme.tick().unwrap(); } } else { error!("Unknown event {}", event.fd); } - - // Handle todos to start new packets if possible - let mut i = 0; - while i < todo.len() { - if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { - socket_fd - .write_response(resp, SignalBehavior::Restart) - .expect("ided: failed to write disk scheme"); - } else { - i += 1; - } - } - - for req in todo.drain(..) { - socket_fd - .write_response( - Response::new(&req, Err(Error::new(ENODEV))), - SignalBehavior::Restart, - ) - .expect("ided: failed to write disk scheme"); - } } std::process::exit(0); diff --git a/storage/ided/src/scheme.rs b/storage/ided/src/scheme.rs deleted file mode 100644 index f41a227579..0000000000 --- a/storage/ided/src/scheme.rs +++ /dev/null @@ -1,323 +0,0 @@ -use std::collections::BTreeMap; -use std::fmt::Write; -use std::str; -use std::sync::{Arc, Mutex}; - -use driver_block::{Disk, DiskWrapper}; -use syscall::schemev2::NewFdFlags; -use syscall::{ - Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, MODE_DIR, MODE_FILE, O_DIRECTORY, - O_STAT, -}; - -use crate::ide::Channel; -use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; - -enum Handle { - List(Vec), // Dir contents buffer - Disk(usize), // Disk index - Partition(usize, u32), // Disk index, partition index -} - -pub struct DiskScheme { - scheme_name: String, - chans: Box<[Arc>]>, - disks: Box<[DiskWrapper>]>, - handles: BTreeMap, - next_id: usize, -} - -impl DiskScheme { - pub fn new( - scheme_name: String, - chans: Vec>>, - disks: Vec>, - ) -> DiskScheme { - DiskScheme { - scheme_name, - chans: chans.into_boxed_slice(), - disks: disks - .into_iter() - .map(DiskWrapper::new) - .collect::>() - .into_boxed_slice(), - handles: BTreeMap::new(), - next_id: 0, - } - } - - pub fn irq(&mut self, chan_i: usize) -> bool { - let _chan = self.chans[chan_i].lock().unwrap(); - //TODO: check chan for irq - true - } - - // Checks if any conflicting handles already exist - fn check_locks(&self, disk_i: usize, part_i_opt: Option) -> Result<()> { - for (_, handle) in self.handles.iter() { - match handle { - Handle::Disk(i) => { - if disk_i == *i { - return Err(Error::new(ENOLCK)); - } - } - Handle::Partition(i, p) => { - if disk_i == *i { - match part_i_opt { - Some(part_i) => { - if part_i == *p { - return Err(Error::new(ENOLCK)); - } - } - None => { - return Err(Error::new(ENOLCK)); - } - } - } - } - _ => (), - } - } - Ok(()) - } -} - -impl SchemeBlock for DiskScheme { - fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result> { - if ctx.uid == 0 { - let path_str = path.trim_matches('/'); - if path_str.is_empty() { - if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { - let mut list = String::new(); - - for (disk_index, disk) in self.disks.iter().enumerate() { - write!(list, "{}\n", disk_index).unwrap(); - - if disk.pt.is_none() { - continue; - } - for part_index in 0..disk.pt.as_ref().unwrap().partitions.len() { - write!(list, "{}p{}\n", disk_index, part_index).unwrap(); - } - } - - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle::List(list.into_bytes())); - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } else { - Err(Error::new(EISDIR)) - } - } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { - let disk_id_str = &path_str[..p_pos]; - if p_pos + 1 >= path_str.len() { - return Err(Error::new(ENOENT)); - } - let part_id_str = &path_str[p_pos + 1..]; - let i = disk_id_str.parse::().or(Err(Error::new(ENOENT)))?; - let p = part_id_str.parse::().or(Err(Error::new(ENOENT)))?; - - if let Some(disk) = self.disks.get(i) { - if disk.pt.is_none() - || disk - .pt - .as_ref() - .unwrap() - .partitions - .get(p as usize) - .is_none() - { - return Err(Error::new(ENOENT)); - } - - self.check_locks(i, Some(p))?; - - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle::Partition(i, p)); - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } else { - Err(Error::new(ENOENT)) - } - } else { - let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; - - if self.disks.get(i).is_some() { - self.check_locks(i, None)?; - - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle::Disk(i)); - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } else { - Err(Error::new(ENOENT)) - } - } - } else { - Err(Error::new(EACCES)) - } - } - - fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { - match *self.handles.get(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref data) => { - stat.st_mode = MODE_DIR; - stat.st_size = data.len() as u64; - Ok(Some(0)) - } - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - stat.st_mode = MODE_FILE; - stat.st_size = disk.size(); - stat.st_blksize = disk.block_size(); - Ok(Some(0)) - } - Handle::Partition(disk_id, part_num) => { - let disk = self.disks.get_mut(disk_id).ok_or(Error::new(EBADF))?; - let size = { - let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; - partition.size - }; - - stat.st_mode = MODE_FILE; // TODO: Block device? - stat.st_size = size * u64::from(disk.block_size()); - stat.st_blksize = disk.block_size(); - stat.st_blocks = size; - Ok(Some(0)) - } - } - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - let mut i = 0; - - let scheme_name = self.scheme_name.as_bytes(); - let mut j = 0; - while i < buf.len() && j < scheme_name.len() { - buf[i] = scheme_name[j]; - i += 1; - j += 1; - } - - if i < buf.len() { - buf[i] = b':'; - i += 1; - } - - match *handle { - Handle::List(_) => (), - Handle::Disk(number) => { - let number_str = format!("{}", number); - let number_bytes = number_str.as_bytes(); - j = 0; - while i < buf.len() && j < number_bytes.len() { - buf[i] = number_bytes[j]; - i += 1; - j += 1; - } - } - Handle::Partition(disk_num, part_num) => { - let path = format!("{}p{}", disk_num, part_num); - let path_bytes = path.as_bytes(); - j = 0; - while i < buf.len() && j < path_bytes.len() { - buf[i] = path_bytes[j]; - i += 1; - j += 1; - } - } - } - - Ok(Some(i)) - } - - fn read( - &mut self, - id: usize, - buf: &mut [u8], - offset: u64, - _flags: u32, - ) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref handle) => { - let src = usize::try_from(offset) - .ok() - .and_then(|o| handle.get(o..)) - .unwrap_or(&[]); - let bytes = src.len().min(buf.len()); - buf[..bytes].copy_from_slice(&src[..bytes]); - Ok(Some(bytes)) - } - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.read(None, block, buf) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.read(Some(part_num as usize), block, buf) - } - } - } - - fn write(&mut self, id: usize, buf: &[u8], offset: u64, _flags: u32) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(_) => Err(Error::new(EBADF)), - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.write(None, block, buf) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.write(Some(part_num as usize), block, buf) - } - } - } - - fn fsize(&mut self, id: usize) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref mut handle) => Ok(Some(handle.len() as u64)), - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - Ok(Some(disk.size())) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block_count = disk - .pt - .as_ref() - .ok_or(Error::new(EBADF))? - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))? - .size; - Ok(Some(u64::from(disk.block_size()) * block_count)) - } - } - } - - fn close(&mut self, id: usize) -> Result> { - self.handles - .remove(&id) - .ok_or(Error::new(EBADF)) - .and(Ok(Some(0))) - } -} diff --git a/storage/lived/Cargo.toml b/storage/lived/Cargo.toml index 57ec2be9fe..034ba80d0a 100644 --- a/storage/lived/Cargo.toml +++ b/storage/lived/Cargo.toml @@ -12,5 +12,5 @@ anyhow = "1" libredox = "0.1.3" redox-daemon = "0.1" redox_syscall = { version = "0.5", features = ["std"] } -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } redox_event = "0.4" +driver-block = { path = "../driver-block" } diff --git a/storage/lived/src/main.rs b/storage/lived/src/main.rs index b2f9096600..f4c2ac15ff 100644 --- a/storage/lived/src/main.rs +++ b/storage/lived/src/main.rs @@ -2,46 +2,26 @@ #![feature(int_roundings)] +use std::collections::BTreeMap; use std::fs::File; use std::os::fd::AsRawFd; -use std::str; +use driver_block::{Disk, DiskScheme}; use libredox::call::MmapArgs; use libredox::flag; -use redox_scheme::{CallerCtx, OpenResult, RequestKind, Scheme, SignalBehavior, Socket}; -use syscall::data::Stat; use syscall::error::*; -use syscall::flag::{MODE_DIR, MODE_FILE}; -use syscall::schemev2::NewFdFlags; use syscall::PAGE_SIZE; use anyhow::{anyhow, bail, Context}; -const LIST: [u8; 2] = *b"0\n"; - -#[repr(usize)] -enum HandleType { - TopLevel = 0, - TheData = 1, -} -impl HandleType { - fn try_from_raw(raw: usize) -> Option { - Some(match raw { - 0 => Self::TopLevel, - 1 => Self::TheData, - _ => return None, - }) - } -} - -pub struct DiskScheme { +struct LiveDisk { the_data: &'static mut [u8], } -impl DiskScheme { - pub fn new() -> anyhow::Result { +impl LiveDisk { + fn new() -> anyhow::Result { let mut phys = 0; let mut size = 0; @@ -93,133 +73,79 @@ impl DiskScheme { std::slice::from_raw_parts_mut(base as *mut u8, size) }; - Ok(DiskScheme { the_data }) + Ok(LiveDisk { the_data }) } } -impl Scheme for DiskScheme { - fn fsize(&mut self, id: usize) -> Result { - Ok( - match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? { - HandleType::TopLevel => LIST.len() as u64, - HandleType::TheData => self.the_data.len() as u64, - }, - ) +impl Disk for LiveDisk { + fn block_size(&self) -> u32 { + 512 } - fn fcntl(&mut self, _id: usize, _cmd: usize, _arg: usize) -> Result { - Ok(0) + fn size(&self) -> u64 { + self.the_data.len() as u64 } - fn fsync(&mut self, _id: usize) -> Result { - Ok(0) - } - - fn close(&mut self, _id: usize) -> Result { - Ok(0) - } - fn xopen(&mut self, path: &str, _flags: usize, ctx: &CallerCtx) -> Result { - if ctx.uid != 0 { - return Err(Error::new(EACCES)); + fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result> { + let block = block as usize; + let block_size = self.block_size() as usize; + if block * block_size + buffer.len() > self.size() as usize { + return Err(syscall::Error::new(EOVERFLOW)); } - - let path_trimmed = path.trim_matches('/'); - - Ok(OpenResult::ThisScheme { - number: match path_trimmed { - "" => HandleType::TopLevel as usize, - "0" => HandleType::TheData as usize, - _ => return Err(Error::new(ENOENT)), - }, - flags: NewFdFlags::POSITIONED, - }) - } - fn read(&mut self, id: usize, buf: &mut [u8], offset: u64, _flags: u32) -> Result { - let data = match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? { - HandleType::TheData => &*self.the_data, - HandleType::TopLevel => &LIST, - }; - - let src = usize::try_from(offset) - .ok() - .and_then(|o| data.get(o..)) - .unwrap_or(&[]); - let byte_count = std::cmp::min(src.len(), buf.len()); - buf[..byte_count].copy_from_slice(&src[..byte_count]); - Ok(byte_count) - } - fn write(&mut self, id: usize, buf: &[u8], offset: u64, _flags: u32) -> Result { - let data = match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? { - HandleType::TheData => &mut *self.the_data, - HandleType::TopLevel => return Err(Error::new(EBADF)), - }; - - let dst = usize::try_from(offset) - .ok() - .and_then(|o| data.get_mut(o..)) - .unwrap_or(&mut []); - let byte_count = std::cmp::min(dst.len(), buf.len()); - dst[..byte_count].copy_from_slice(&buf[..byte_count]); - Ok(byte_count) + buffer + .copy_from_slice(&self.the_data[block * block_size..block * block_size + buffer.len()]); + Ok(Some(block_size)) } - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { - let path = match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? { - HandleType::TopLevel => "", - HandleType::TheData => "0", - }; - - let src = format!("disk.live:{}", path).into_bytes(); - - let byte_count = std::cmp::min(buf.len(), src.len()); - buf[..byte_count].copy_from_slice(&src[..byte_count]); - - Ok(byte_count) - } - fn fstat(&mut self, id: usize, stat_buf: &mut Stat) -> Result { - let (len, mode) = match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? { - HandleType::TheData => (self.the_data.len(), MODE_FILE | 0o644), - HandleType::TopLevel => (LIST.len(), MODE_DIR | 0o755), - }; - - *stat_buf = Stat { - st_mode: mode, - st_uid: 0, - st_gid: 0, - st_size: len.try_into().map_err(|_| Error::new(EOVERFLOW))?, - ..Stat::default() - }; - - Ok(0) + fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result> { + let block = block as usize; + let block_size = self.block_size() as usize; + if block * block_size + buffer.len() > self.size() as usize { + return Err(syscall::Error::new(EOVERFLOW)); + } + self.the_data[block * block_size..block * block_size + buffer.len()] + .copy_from_slice(buffer); + Ok(Some(block_size)) } } + fn main() -> anyhow::Result<()> { redox_daemon::Daemon::new(move |daemon| { - let socket_fd = Socket::create("disk.live").expect("failed to open scheme"); - let mut scheme = DiskScheme::new().unwrap_or_else(|err| { - eprintln!("failed to initialize livedisk scheme: {}", err); - std::process::exit(1) - }); + let event_queue = event::EventQueue::new().unwrap(); + + event::user_data! { + enum Event { + Scheme, + } + }; + + let mut scheme = DiskScheme::new( + "disk.live".to_owned(), + BTreeMap::from([( + 0, + LiveDisk::new().unwrap_or_else(|err| { + eprintln!("failed to initialize livedisk scheme: {}", err); + std::process::exit(1) + }), + )]), + ); + + libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); + + event_queue + .subscribe( + scheme.event_handle().raw(), + Event::Scheme, + event::EventFlags::READ, + ) + .unwrap(); + daemon.ready().expect("failed to signal readiness"); - loop { - let req = match socket_fd - .next_request(SignalBehavior::Restart) - .expect("failed to get next request") - { - Some(r) => { - if let RequestKind::Call(c) = r.kind() { - c - } else { - continue; - } - } - None => break, - }; - let resp = req.handle_scheme(&mut scheme); - socket_fd - .write_response(resp, SignalBehavior::Restart) - .expect("failed to write packet"); + for event in event_queue { + match event.unwrap().user_data { + Event::Scheme => scheme.tick().unwrap(), + } } std::process::exit(0); diff --git a/storage/nvmed/Cargo.toml b/storage/nvmed/Cargo.toml index 8a6d1c6663..3650871a87 100644 --- a/storage/nvmed/Cargo.toml +++ b/storage/nvmed/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "nvmed" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] arrayvec = "0.5" @@ -11,7 +11,6 @@ futures = "0.3" log = "0.4" redox-daemon = "0.1" redox_syscall = { version = "0.5", features = ["std"] } -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } redox_event = "0.4" smallvec = "1" diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 93bd7e47c9..d53189d1f2 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -5,15 +5,15 @@ use std::ptr::NonNull; use std::sync::Arc; use std::{slice, usize}; +use driver_block::{Disk, DiskScheme}; use pcid_interface::{PciFeature, PciFeatureInfo, PciFunction, PciFunctionHandle}; -use redox_scheme::{RequestKind, SignalBehavior, Socket}; use syscall::Result; +use crate::nvme::NvmeNamespace; + use self::nvme::{InterruptMethod, InterruptSources, Nvme}; -use self::scheme::DiskScheme; mod nvme; -mod scheme; /// Get the most optimal yet functional interrupt mechanism: either (in the order of preference): /// MSI-X, MSI, and INTx# pin. Returns both runtime interrupt structures (MSI/MSI-X capability @@ -140,6 +140,26 @@ fn get_int_method( } } +struct NvmeDisk(Arc, NvmeNamespace); + +impl Disk for NvmeDisk { + fn block_size(&self) -> u32 { + self.1.block_size.try_into().unwrap() + } + + fn size(&self) -> u64 { + self.1.blocks * self.1.block_size + } + + fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result> { + self.0.namespace_read(self.1, block, buffer) + } + + fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result> { + self.0.namespace_write(self.1, block, buffer) + } +} + fn main() { redox_daemon::Daemon::new(daemon).expect("nvmed: failed to daemonize"); } @@ -161,8 +181,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let address = unsafe { pcid_handle.map_bar(0).ptr }; - let socket = Socket::create(&scheme_name).expect("nvmed: failed to create disk scheme"); - daemon.ready().expect("nvmed: failed to signal readiness"); let (reactor_sender, reactor_receiver) = crossbeam_channel::unbounded(); @@ -185,40 +203,35 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { reactor_receiver, ); let namespaces = nvme.init_with_queues(); + let event_queue = event::EventQueue::new().unwrap(); + + event::user_data! { + enum Event { + Scheme, + } + }; + + let mut scheme = DiskScheme::new( + scheme_name, + namespaces + .into_iter() + .map(|(k, ns)| (k, NvmeDisk(nvme.clone(), ns))) + .collect(), + ); libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); - let mut scheme = DiskScheme::new(scheme_name, nvme, namespaces); - let mut todo = Vec::new(); - loop { - // TODO: Use a proper event queue once interrupt support is back. - match socket - .next_request(SignalBehavior::Restart) - .expect("nvmed: failed to read disk scheme") - { - None => { - break; - } - Some(req) => { - if let RequestKind::Call(c) = req.kind() { - todo.push(c); - } else { - // TODO: cancellation - continue; - } - } - } + event_queue + .subscribe( + scheme.event_handle().raw(), + Event::Scheme, + event::EventFlags::READ, + ) + .unwrap(); - let mut i = 0; - while i < todo.len() { - if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { - let _req = todo.remove(i); - socket - .write_response(resp, SignalBehavior::Restart) - .expect("nvmed: failed to write disk scheme"); - } else { - i += 1; - } + for event in event_queue { + match event.unwrap().user_data { + Event::Scheme => scheme.tick().unwrap(), } } diff --git a/storage/nvmed/src/scheme.rs b/storage/nvmed/src/scheme.rs deleted file mode 100644 index bd864441dd..0000000000 --- a/storage/nvmed/src/scheme.rs +++ /dev/null @@ -1,336 +0,0 @@ -use std::collections::BTreeMap; -use std::convert::{TryFrom, TryInto}; -use std::fmt::Write; -use std::str; -use std::sync::Arc; - -use driver_block::{Disk, DiskWrapper}; -use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; -use syscall::schemev2::NewFdFlags; -use syscall::{ - Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, MODE_DIR, MODE_FILE, O_DIRECTORY, - O_STAT, -}; - -use crate::nvme::{Nvme, NvmeNamespace}; - -enum Handle { - List(Vec), // entries - Disk(u32), // disk num - Partition(u32, u32), // disk num, part num -} - -struct NvmeDisk(Arc, NvmeNamespace); - -impl Disk for NvmeDisk { - fn block_size(&self) -> u32 { - self.1.block_size.try_into().unwrap() - } - - fn size(&self) -> u64 { - self.1.blocks * self.1.block_size - } - - fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result> { - self.0.namespace_read(self.1, block, buffer) - } - - fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result> { - self.0.namespace_write(self.1, block, buffer) - } -} - -pub struct DiskScheme { - scheme_name: String, - disks: BTreeMap>, - handles: BTreeMap, - next_id: usize, -} - -impl DiskScheme { - pub fn new( - scheme_name: String, - nvme: Arc, - disks: BTreeMap, - ) -> DiskScheme { - DiskScheme { - scheme_name, - disks: disks - .into_iter() - .map(|(k, ns)| (k, DiskWrapper::new(NvmeDisk(nvme.clone(), ns)))) - .collect(), - handles: BTreeMap::new(), - next_id: 0, - } - } - - // Checks if any conflicting handles already exist - fn check_locks(&self, disk_i: u32, part_i_opt: Option) -> Result<()> { - for (_, handle) in self.handles.iter() { - match handle { - Handle::Disk(i) => { - if disk_i == *i { - return Err(Error::new(ENOLCK)); - } - } - Handle::Partition(i, p) => { - if disk_i == *i { - match part_i_opt { - Some(part_i) => { - if part_i == *p { - return Err(Error::new(ENOLCK)); - } - } - None => { - return Err(Error::new(ENOLCK)); - } - } - } - } - _ => (), - } - } - Ok(()) - } -} - -impl SchemeBlock for DiskScheme { - fn xopen( - &mut self, - path_str: &str, - flags: usize, - ctx: &CallerCtx, - ) -> Result> { - if ctx.uid != 0 { - return Err(Error::new(EACCES)); - } - let path_str = path_str.trim_matches('/'); - - let handle = if path_str.is_empty() { - if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { - let mut list = String::new(); - - for (nsid, disk) in self.disks.iter() { - write!(list, "{}\n", nsid).unwrap(); - - if disk.pt.is_none() { - continue; - } - for part_num in 0..disk.pt.as_ref().unwrap().partitions.len() { - write!(list, "{}p{}\n", nsid, part_num).unwrap(); - } - } - - Handle::List(list.into_bytes()) - } else { - return Err(Error::new(EISDIR)); - } - } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { - let nsid_str = &path_str[..p_pos]; - - if p_pos + 1 >= path_str.len() { - return Err(Error::new(ENOENT)); - } - let part_num_str = &path_str[p_pos + 1..]; - - let nsid = nsid_str.parse::().or(Err(Error::new(ENOENT)))?; - let part_num = part_num_str.parse::().or(Err(Error::new(ENOENT)))?; - - if let Some(disk) = self.disks.get(&nsid) { - if disk - .pt - .as_ref() - .ok_or(Error::new(ENOENT))? - .partitions - .get(part_num as usize) - .is_some() - { - self.check_locks(nsid, Some(part_num))?; - - Handle::Partition(nsid, part_num) - } else { - return Err(Error::new(ENOENT)); - } - } else { - return Err(Error::new(ENOENT)); - } - } else { - let nsid = path_str.parse::().or(Err(Error::new(ENOENT)))?; - - if self.disks.contains_key(&nsid) { - self.check_locks(nsid, None)?; - Handle::Disk(nsid) - } else { - return Err(Error::new(ENOENT)); - } - }; - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, handle); - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } - - fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { - match *self.handles.get(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref data) => { - stat.st_mode = MODE_DIR; - stat.st_size = data.len() as u64; - Ok(Some(0)) - } - Handle::Disk(number) => { - let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - stat.st_mode = MODE_FILE; - stat.st_blocks = disk.disk().1.blocks; - stat.st_blksize = disk.block_size(); - stat.st_size = disk.size(); - Ok(Some(0)) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; - let part = disk - .pt - .as_ref() - .ok_or(Error::new(EBADF))? - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; - stat.st_mode = MODE_FILE; - stat.st_size = part.size * u64::from(disk.block_size()); - stat.st_blocks = part.size; - stat.st_blksize = disk.block_size(); - Ok(Some(0)) - } - } - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - let mut i = 0; - - let scheme_name = self.scheme_name.as_bytes(); - let mut j = 0; - while i < buf.len() && j < scheme_name.len() { - buf[i] = scheme_name[j]; - i += 1; - j += 1; - } - - if i < buf.len() { - buf[i] = b':'; - i += 1; - } - - match *handle { - Handle::List(_) => (), - Handle::Disk(number) => { - let number_str = format!("{}", number); - let number_bytes = number_str.as_bytes(); - j = 0; - while i < buf.len() && j < number_bytes.len() { - buf[i] = number_bytes[j]; - i += 1; - j += 1; - } - } - Handle::Partition(disk_num, part_num) => { - let number_str = format!("{}p{}", disk_num, part_num); - let number_bytes = number_str.as_bytes(); - j = 0; - while i < buf.len() && j < number_bytes.len() { - buf[i] = number_bytes[j]; - i += 1; - j += 1; - } - } - } - - Ok(Some(i)) - } - - fn read( - &mut self, - id: usize, - buf: &mut [u8], - offset: u64, - _fcntl_flags: u32, - ) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref handle) => { - let src = usize::try_from(offset) - .ok() - .and_then(|o| handle.get(o..)) - .unwrap_or(&[]); - let count = core::cmp::min(src.len(), buf.len()); - buf[..count].copy_from_slice(&src[..count]); - Ok(Some(count)) - } - Handle::Disk(number) => { - let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.read(None, block, buf) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.read(Some(part_num as usize), block, buf) - } - } - } - - fn write( - &mut self, - id: usize, - buf: &[u8], - offset: u64, - _fcntl_flags: u32, - ) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(_) => Err(Error::new(EBADF)), - Handle::Disk(number) => { - let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.write(None, block, buf) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.write(Some(part_num as usize), block, buf) - } - } - } - - fn fsize(&mut self, id: usize) -> Result> { - Ok(Some( - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref handle) => handle.len() as u64, - Handle::Disk(number) => { - let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - disk.size() - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; - let part = disk - .pt - .as_ref() - .ok_or(Error::new(EBADF))? - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; - - part.size * u64::from(disk.block_size()) - } - }, - )) - } - - fn close(&mut self, id: usize) -> Result> { - self.handles - .remove(&id) - .ok_or(Error::new(EBADF)) - .and(Ok(Some(0))) - } -} diff --git a/storage/virtio-blkd/Cargo.toml b/storage/virtio-blkd/Cargo.toml index 2b2a663565..34cc370cae 100644 --- a/storage/virtio-blkd/Cargo.toml +++ b/storage/virtio-blkd/Cargo.toml @@ -13,8 +13,8 @@ futures = { version = "0.3.28", features = ["executor"] } spin = "*" redox-daemon = "0.1" +redox_event = "0.4" redox_syscall = { version = "0.5", features = ["std"] } -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } common = { path = "../../common" } driver-block = { path = "../driver-block" } diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index ac94312eef..7503b477d7 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -1,8 +1,9 @@ #![deny(trivial_numeric_casts, unused_allocation)] +use std::collections::BTreeMap; use std::sync::{Arc, Weak}; -use redox_scheme::{RequestKind, SignalBehavior, Socket}; +use driver_block::DiskScheme; use static_assertions::const_assert_eq; use pcid_interface::*; @@ -15,6 +16,8 @@ mod scheme; use thiserror::Error; +use crate::scheme::VirtioDisk; + #[derive(Debug, Error)] pub enum Error { #[error("capability {0:?} not found")] @@ -140,31 +143,37 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let scheme_name = format!("disk.{}", name); - let socket_fd = Socket::create(&scheme_name).map_err(Error::SyscallError)?; + let event_queue = event::EventQueue::new().unwrap(); - let mut scheme = scheme::DiskScheme::new(queue, device_space); + event::user_data! { + enum Event { + Scheme, + } + }; + + let mut scheme = DiskScheme::new( + scheme_name, + BTreeMap::from([(0, VirtioDisk::new(queue, device_space))]), + ); + + libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); + + event_queue + .subscribe( + scheme.event_handle().raw(), + Event::Scheme, + event::EventFlags::READ, + ) + .unwrap(); deamon.ready().expect("virtio-blkd: failed to deamonize"); - loop { - let req = match socket_fd - .next_request(SignalBehavior::Restart) - .expect("virtio-blkd: failed to read disk scheme") - { - Some(r) => { - if let RequestKind::Call(c) = r.kind() { - c - } else { - continue; - } - } - None => break, - }; - let resp = req.handle_scheme_block(&mut scheme).expect("TODO: block?"); - socket_fd - .write_response(resp, SignalBehavior::Restart) - .expect("virtio-blkd: failed to write to disk scheme"); + for event in event_queue { + match event.unwrap().user_data { + Event::Scheme => scheme.tick().unwrap(), + } } + Ok(()) } diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index 974573da51..074f2ff61c 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -1,17 +1,6 @@ -use std::collections::BTreeMap; - -use std::fmt::Write; use std::sync::Arc; use common::dma::Dma; -use driver_block::DiskWrapper; - -use redox_scheme::CallerCtx; -use redox_scheme::OpenResult; -use redox_scheme::SchemeBlock; -use syscall::error::*; -use syscall::flag::*; -use syscall::schemev2::NewFdFlags; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; use virtio_core::transport::Queue; @@ -19,8 +8,6 @@ use crate::BlockDeviceConfig; use crate::BlockRequestTy; use crate::BlockVirtRequest; -const BLK_SIZE: u64 = 512; - trait BlkExtension { async fn read(&self, block: u64, target: &mut [u8]) -> usize; async fn write(&self, block: u64, target: &[u8]) -> usize; @@ -86,13 +73,13 @@ impl BlkExtension for Queue<'_> { } } -struct VirtioDisk<'a> { +pub(crate) struct VirtioDisk<'a> { queue: Arc>, cfg: BlockDeviceConfig, } impl<'a> VirtioDisk<'a> { - pub fn new(queue: Arc>, cfg: BlockDeviceConfig) -> Self { + pub(crate) fn new(queue: Arc>, cfg: BlockDeviceConfig) -> Self { Self { queue, cfg } } } @@ -118,203 +105,3 @@ impl driver_block::Disk for VirtioDisk<'_> { ))) } } - -pub enum Handle { - Partition { - /// Partition Number - number: u32, - }, - - List { - entries: Vec, - }, - - Disk, -} - -pub struct DiskScheme<'a> { - disk: DiskWrapper>, - next_id: usize, - handles: BTreeMap, -} - -impl<'a> DiskScheme<'a> { - pub fn new(queue: Arc>, cfg: BlockDeviceConfig) -> Self { - Self { - disk: DiskWrapper::new(VirtioDisk::new(queue, cfg)), - next_id: 0, - handles: BTreeMap::new(), - } - } -} - -impl<'a> SchemeBlock for DiskScheme<'a> { - fn xopen( - &mut self, - path: &str, - flags: usize, - _ctx: &CallerCtx, - ) -> syscall::Result> { - log::info!("virtiod: open: {}", path); - - let path_str = path.trim_matches('/'); - if path_str.is_empty() { - if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { - let mut list = String::new(); - // FIXME: The zero is the disk identifier (look in the nvmed scheme, it set's this - // to the namespace id). - write!(list, "{}\n", 0).unwrap(); - - if let Some(part_table) = &self.disk.pt { - for part_num in 0..part_table.partitions.len() { - write!(list, "{}p{}\n", 0, part_num).unwrap(); - } - } - - let id = self.next_id; - self.next_id += 1; - self.handles.insert( - id, - Handle::List { - entries: list.into_bytes(), - }, - ); - - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } else { - return Err(syscall::Error::new(EISDIR)); - } - } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { - let _nsid_str = &path_str[..p_pos]; - - if p_pos + 1 >= path_str.len() { - return Err(Error::new(ENOENT)); - } - let part_num_str = &path_str[p_pos + 1..]; - let part_num = part_num_str.parse::().unwrap(); - - let part_table = self.disk.pt.as_ref().unwrap(); - let _part = part_table.partitions.get(part_num as usize).unwrap(); - - let id = self.next_id; - self.next_id += 1; - self.handles - .insert(id, Handle::Partition { number: part_num }); - - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } else { - let nsid = path_str.parse::().unwrap(); - assert_eq!(nsid, 0); - - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle::Disk); - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } - } - - fn read( - &mut self, - id: usize, - buf: &mut [u8], - offset: u64, - _fcntl_flags: u32, - ) -> syscall::Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List { ref mut entries } => { - let src = usize::try_from(offset) - .ok() - .and_then(|o| entries.get(o..)) - .unwrap_or(&[]); - let count = core::cmp::min(src.len(), buf.len()); - buf[..count].copy_from_slice(&src[..count]); - Ok(Some(count)) - } - Handle::Disk => { - let block = offset / u64::from(self.disk.block_size()); - self.disk.read(None, block, buf) - } - Handle::Partition { number } => { - let block = offset / u64::from(self.disk.block_size()); - self.disk.read(Some(number as usize), block, buf) - } - } - } - - fn write( - &mut self, - id: usize, - buf: &[u8], - offset: u64, - _fcntl_flags: u32, - ) -> syscall::Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List { .. } => Err(Error::new(EBADF)), - Handle::Disk => { - let block = offset / u64::from(self.disk.block_size()); - self.disk.write(None, block, buf) - } - Handle::Partition { number } => { - let block = offset / u64::from(self.disk.block_size()); - self.disk.write(Some(number as usize), block, buf) - } - } - } - - fn fsize(&mut self, id: usize) -> syscall::Result> { - Ok(Some( - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List { ref entries } => { - let len = entries.len() as u64; - log::debug!("list: part_len={len:?}"); - - len - } - - Handle::Partition { number } => { - let part_table = self.disk.pt.as_ref().unwrap(); - let part = part_table - .partitions - .get(number as usize) - .ok_or(Error::new(EBADF))?; - - // Partition size in bytes. - let len = part.size * BLK_SIZE; - - log::debug!("part: part_len={len:?}"); - - len - } - - Handle::Disk => self.disk.size(), - }, - )) - } - - fn fpath(&mut self, _id: usize, _buf: &mut [u8]) -> syscall::Result> { - todo!() - } - - fn fstat(&mut self, id: usize, _stat: &mut syscall::Stat) -> syscall::Result> { - match self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List { .. } => Ok(Some(0)), - Handle::Disk { .. } | Handle::Partition { .. } => todo!(), - } - } - - fn close(&mut self, id: usize) -> syscall::Result> { - self.handles - .remove(&id) - .ok_or(Error::new(EBADF)) - .and(Ok(Some(0))) - } -}