diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs index 6b10c14b26..02f771e475 100644 --- a/storage/driver-block/src/lib.rs +++ b/storage/driver-block/src/lib.rs @@ -8,8 +8,7 @@ use partitionlib::{LogicalBlockSize, PartitionTable}; /// `read_fn` will be called with a block number to be read, and a buffer to be filled. /// `read_fn` must return a full block of data. /// Result will be the number of bytes read. -// FIXME make private once nvmed uses the DiskWrapper defined in this crate -pub fn block_read( +fn block_read( offset: u64, blksize: u32, buf: &mut [u8], @@ -67,9 +66,10 @@ pub struct DiskWrapper { } impl DiskWrapper { - fn pt(disk: &mut dyn Disk) -> Option { + pub fn pt(disk: &mut dyn Disk) -> Option { let bs = match disk.block_length() { Ok(512) => LogicalBlockSize::Lb512, + Ok(4096) => LogicalBlockSize::Lb4096, _ => return None, }; struct Device<'a> { diff --git a/storage/nvmed/src/scheme.rs b/storage/nvmed/src/scheme.rs index 30dd5d82d5..ee27527d9e 100644 --- a/storage/nvmed/src/scheme.rs +++ b/storage/nvmed/src/scheme.rs @@ -1,11 +1,11 @@ use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; use std::fmt::Write; -use std::io; -use std::io::prelude::*; +use std::str; use std::sync::Arc; -use std::{cmp, str}; +use driver_block::Disk; +use partitionlib::PartitionTable; use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; use syscall::schemev2::NewFdFlags; use syscall::{ @@ -15,14 +15,32 @@ use syscall::{ use crate::nvme::{Nvme, NvmeNamespace}; -use partitionlib::{LogicalBlockSize, PartitionTable}; - enum Handle { List(Vec), // entries Disk(u32), // disk num Partition(u32, u32), // disk num, part num } +struct NamespaceAndNvme<'a>(&'a Nvme, NvmeNamespace); + +impl Disk for NamespaceAndNvme<'_> { + fn block_length(&mut self) -> syscall::error::Result { + Ok(self.1.block_size.try_into().unwrap()) + } + + fn size(&mut 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 DiskWrapper { inner: NvmeNamespace, pt: Option, @@ -36,91 +54,7 @@ impl AsRef for DiskWrapper { impl DiskWrapper { fn pt(disk: NvmeNamespace, nvme: &Nvme) -> Option { - let bs = match disk.block_size { - 512 => LogicalBlockSize::Lb512, - 4096 => LogicalBlockSize::Lb4096, - _ => return None, - }; - struct Device<'a> { - disk: NvmeNamespace, - nvme: &'a Nvme, - offset: u64, - } - - impl<'a> Seek for Device<'a> { - fn seek(&mut self, from: io::SeekFrom) -> io::Result { - let size_u = self.disk.blocks * self.disk.block_size; - let size = i64::try_from(size_u).or(Err(io::Error::new( - io::ErrorKind::Other, - "Disk larger than 2^63 - 1 bytes", - )))?; - - self.offset = match from { - io::SeekFrom::Start(new_pos) => cmp::min(size_u, new_pos), - io::SeekFrom::Current(new_pos) => { - cmp::max(0, cmp::min(size, self.offset as i64 + new_pos)) as u64 - } - io::SeekFrom::End(new_pos) => { - cmp::max(0, cmp::min(size + new_pos, size)) as u64 - } - }; - - Ok(self.offset) - } - } - - impl<'a> Read for Device<'a> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let blksize = self.disk.block_size; - let size_in_blocks = self.disk.blocks; - - let disk = self.disk; - let nvme = &mut self.nvme; - - let read_block = |block: u64, block_bytes: &mut [u8]| { - if block >= size_in_blocks { - return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW)); - } - loop { - match nvme - .namespace_read(disk, block, block_bytes) - .map_err(|err| io::Error::from_raw_os_error(err.errno))? - { - Some(bytes) => { - assert_eq!(bytes, block_bytes.len()); - assert_eq!(bytes, blksize as usize); - return Ok(()); - } - None => { - std::thread::yield_now(); - continue; - } // TODO: Does this driver have (internal) error handling at all? - } - } - }; - let bytes_read = driver_block::block_read( - self.offset, - blksize - .try_into() - .expect("Unreasonable block size above 2^32 bytes"), - buf, - read_block, - )?; - self.offset += bytes_read as u64; - Ok(bytes_read) - } - } - - partitionlib::get_partitions( - &mut Device { - disk, - nvme, - offset: 0, - }, - bs, - ) - .ok() - .flatten() + driver_block::DiskWrapper::pt(&mut NamespaceAndNvme(nvme, disk)) } fn new(inner: NvmeNamespace, nvme: &Nvme) -> Self { Self { diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index 8880779c59..d4727b9278 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -1,13 +1,10 @@ use std::collections::BTreeMap; -use std::io::Read; -use std::io::Result as IoResult; -use std::io::Seek; use std::fmt::Write; use std::sync::Arc; use common::dma::Dma; -use partitionlib::LogicalBlockSize; +use driver_block::DiskWrapper; use partitionlib::PartitionTable; use redox_scheme::CallerCtx; @@ -121,85 +118,31 @@ impl<'a> DiskScheme<'a> { part_table: None, }; - struct VirtioShim<'a, 'b> { - scheme: &'b DiskScheme<'a>, - offset: u64, - } - - impl<'a, 'b> Read for VirtioShim<'a, 'b> { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - let read_block = - |block: u64, block_bytes: &mut [u8]| -> Result<(), std::io::Error> { - let req = Dma::new(BlockVirtRequest { - ty: BlockRequestTy::In, - reserved: 0, - sector: block, - }) - .unwrap(); - - let result = Dma::new([0u8; 512]).unwrap(); - let status = Dma::new(u8::MAX).unwrap(); - - let chain = ChainBuilder::new() - .chain(Buffer::new(&req)) - .chain(Buffer::new(&result).flags(DescriptorFlags::WRITE_ONLY)) - .chain(Buffer::new(&status).flags(DescriptorFlags::WRITE_ONLY)) - .build(); - - futures::executor::block_on(self.scheme.queue.send(chain)); - assert_eq!(*status, 0); - - let size = core::cmp::min(block_bytes.len(), result.len()); - block_bytes[..size].copy_from_slice(&result.as_slice()[..size]); - Ok(()) - }; - - let bytes_read = - driver_block::block_read(self.offset, 512, buf, read_block).unwrap(); - self.offset += bytes_read as u64; - Ok(bytes_read) - } - } - - impl<'a, 'b> Seek for VirtioShim<'a, 'b> { - fn seek(&mut self, from: std::io::SeekFrom) -> IoResult { - let size_u = self.scheme.cfg.capacity() * self.scheme.cfg.block_size() as u64; - let size = i64::try_from(size_u).or(Err(std::io::Error::new( - std::io::ErrorKind::Other, - "Disk larger than 2^63 - 1 bytes", - )))?; - - self.offset = match from { - std::io::SeekFrom::Start(new_pos) => std::cmp::min(size_u, new_pos), - std::io::SeekFrom::Current(new_pos) => { - std::cmp::max(0, std::cmp::min(size, self.offset as i64 + new_pos)) as u64 - } - std::io::SeekFrom::End(new_pos) => { - std::cmp::max(0, std::cmp::min(size + new_pos, size)) as u64 - } - }; - - Ok(self.offset) - } - } - - let mut shim = VirtioShim { - scheme: &this, - offset: 0, - }; - - //driver_block::DiskWrapper::new(disk) - - // FIXME use DiskWrapper instead - let part_table = partitionlib::get_partitions(&mut shim, LogicalBlockSize::Lb512) - .ok() - .flatten(); - - this.part_table = part_table; + this.part_table = DiskWrapper::pt(&mut this); this } } +impl driver_block::Disk for DiskScheme<'_> { + fn block_length(&mut self) -> syscall::error::Result { + Ok(self.cfg.block_size()) + } + + fn size(&mut self) -> u64 { + self.cfg.capacity() * self.cfg.block_size() as u64 + } + + fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result> { + Ok(Some(futures::executor::block_on( + self.queue.read(block, buffer), + ))) + } + + fn write(&mut self, _block: u64, _buffer: &[u8]) -> syscall::Result> { + todo!() + } +} + impl<'a> SchemeBlock for DiskScheme<'a> { fn xopen( &mut self,