storage: Use DiskWrapper::pt in nvmed and virtio-blkd

This commit is contained in:
bjorn3
2025-03-07 20:58:01 +01:00
parent ebdfc89e7a
commit f01a8c8d3e
3 changed files with 49 additions and 172 deletions
+3 -3
View File
@@ -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<PartitionTable> {
pub fn pt(disk: &mut dyn Disk) -> Option<PartitionTable> {
let bs = match disk.block_length() {
Ok(512) => LogicalBlockSize::Lb512,
Ok(4096) => LogicalBlockSize::Lb4096,
_ => return None,
};
struct Device<'a> {
+24 -90
View File
@@ -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<u8>), // 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<u32> {
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<Option<usize>> {
self.0.namespace_read(self.1, block, buffer)
}
fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result<Option<usize>> {
self.0.namespace_write(self.1, block, buffer)
}
}
pub struct DiskWrapper {
inner: NvmeNamespace,
pt: Option<PartitionTable>,
@@ -36,91 +54,7 @@ impl AsRef<NvmeNamespace> for DiskWrapper {
impl DiskWrapper {
fn pt(disk: NvmeNamespace, nvme: &Nvme) -> Option<PartitionTable> {
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<u64> {
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<usize> {
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 {
+22 -79
View File
@@ -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<usize> {
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<u64> {
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<u32> {
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<Option<usize>> {
Ok(Some(futures::executor::block_on(
self.queue.read(block, buffer),
)))
}
fn write(&mut self, _block: u64, _buffer: &[u8]) -> syscall::Result<Option<usize>> {
todo!()
}
}
impl<'a> SchemeBlock for DiskScheme<'a> {
fn xopen(
&mut self,