Merge branch 'storage_cleanup' into 'master'
Deduplicate a fair bit of code between block device drivers See merge request redox-os/drivers!248
This commit is contained in:
Generated
-2
@@ -854,7 +854,6 @@ dependencies = [
|
||||
"futures",
|
||||
"libredox",
|
||||
"log",
|
||||
"partitionlib",
|
||||
"pcid",
|
||||
"redox-daemon",
|
||||
"redox-scheme 0.3.0",
|
||||
@@ -1672,7 +1671,6 @@ dependencies = [
|
||||
"futures",
|
||||
"libredox",
|
||||
"log",
|
||||
"partitionlib",
|
||||
"pcid",
|
||||
"redox-daemon",
|
||||
"redox-scheme 0.3.0",
|
||||
|
||||
@@ -154,11 +154,11 @@ impl DiskATA {
|
||||
}
|
||||
|
||||
impl Disk for DiskATA {
|
||||
fn id(&self) -> usize {
|
||||
self.id
|
||||
fn block_size(&self) -> u32 {
|
||||
512
|
||||
}
|
||||
|
||||
fn size(&mut self) -> u64 {
|
||||
fn size(&self) -> u64 {
|
||||
self.size
|
||||
}
|
||||
|
||||
@@ -181,8 +181,4 @@ impl Disk for DiskATA {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn block_length(&mut self) -> Result<u32> {
|
||||
Ok(512)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ pub struct DiskATAPI {
|
||||
// Just using the same buffer size as DiskATA
|
||||
// Although the sector size is different (and varies)
|
||||
buf: Dma<[u8; 256 * 512]>,
|
||||
blk_count: u32,
|
||||
blk_size: u32,
|
||||
}
|
||||
|
||||
impl DiskATAPI {
|
||||
@@ -38,12 +40,20 @@ impl DiskATAPI {
|
||||
.unwrap_or_else(|_| unreachable!());
|
||||
|
||||
let mut fb = unsafe { Dma::zeroed()?.assume_init() };
|
||||
let buf = unsafe { Dma::zeroed()?.assume_init() };
|
||||
let mut buf = unsafe { Dma::zeroed()?.assume_init() };
|
||||
|
||||
port.init(&mut clb, &mut ctbas, &mut fb);
|
||||
|
||||
let size = unsafe { port.identify_packet(&mut clb, &mut ctbas).unwrap_or(0) };
|
||||
|
||||
let mut cmd = [0; 16];
|
||||
cmd[0] = SCSI_READ_CAPACITY;
|
||||
port.atapi_dma(&cmd, 8, &mut clb, &mut ctbas, &mut buf)?;
|
||||
|
||||
// Instead of a count, contains number of last LBA, so add 1
|
||||
let blk_count = BigEndian::read_u32(&buf[0..4]) + 1;
|
||||
let blk_size = BigEndian::read_u32(&buf[4..8]);
|
||||
|
||||
Ok(DiskATAPI {
|
||||
id,
|
||||
port,
|
||||
@@ -52,41 +62,25 @@ impl DiskATAPI {
|
||||
ctbas,
|
||||
_fb: fb,
|
||||
buf,
|
||||
blk_count,
|
||||
blk_size,
|
||||
})
|
||||
}
|
||||
|
||||
fn read_capacity(&mut self) -> Result<(u32, u32)> {
|
||||
// TODO: only query when needed (disk changed)
|
||||
|
||||
let mut cmd = [0; 16];
|
||||
cmd[0] = SCSI_READ_CAPACITY;
|
||||
self.port
|
||||
.atapi_dma(&cmd, 8, &mut self.clb, &mut self.ctbas, &mut self.buf)?;
|
||||
|
||||
// Instead of a count, contains number of last LBA, so add 1
|
||||
let blk_count = BigEndian::read_u32(&self.buf[0..4]) + 1;
|
||||
let blk_size = BigEndian::read_u32(&self.buf[4..8]);
|
||||
|
||||
Ok((blk_count, blk_size))
|
||||
}
|
||||
}
|
||||
|
||||
impl Disk for DiskATAPI {
|
||||
fn id(&self) -> usize {
|
||||
self.id
|
||||
fn block_size(&self) -> u32 {
|
||||
self.blk_size
|
||||
}
|
||||
|
||||
fn size(&mut self) -> u64 {
|
||||
match self.read_capacity() {
|
||||
Ok((blk_count, blk_size)) => (blk_count as u64) * (blk_size as u64),
|
||||
Err(_) => 0, // XXX
|
||||
}
|
||||
fn size(&self) -> u64 {
|
||||
u64::from(self.blk_count) * u64::from(self.blk_size)
|
||||
}
|
||||
|
||||
fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result<Option<usize>> {
|
||||
// TODO: Handle audio CDs, which use special READ CD command
|
||||
|
||||
let blk_len = self.block_length()?;
|
||||
let blk_len = self.blk_size;
|
||||
let sectors = buffer.len() as u32 / blk_len;
|
||||
|
||||
fn read10_cmd(block: u32, count: u16) -> [u8; 16] {
|
||||
@@ -151,8 +145,4 @@ impl Disk for DiskATAPI {
|
||||
fn write(&mut self, _block: u64, _buffer: &[u8]) -> Result<Option<usize>> {
|
||||
Err(Error::new(EBADF)) // TODO: Implement writing
|
||||
}
|
||||
|
||||
fn block_length(&mut self) -> Result<u32> {
|
||||
Ok(self.read_capacity()?.1)
|
||||
}
|
||||
}
|
||||
|
||||
+15
-52
@@ -7,8 +7,8 @@ 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, EOVERFLOW, MODE_DIR, MODE_FILE,
|
||||
O_DIRECTORY, O_STAT,
|
||||
Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, MODE_DIR, MODE_FILE, O_DIRECTORY,
|
||||
O_STAT,
|
||||
};
|
||||
|
||||
use crate::ahci::hba::HbaMem;
|
||||
@@ -22,7 +22,7 @@ enum Handle {
|
||||
pub struct DiskScheme {
|
||||
scheme_name: String,
|
||||
hba_mem: &'static mut HbaMem,
|
||||
disks: Box<[DiskWrapper]>,
|
||||
disks: Box<[DiskWrapper<Box<dyn Disk>>]>,
|
||||
handles: BTreeMap<usize, Handle>,
|
||||
next_id: usize,
|
||||
}
|
||||
@@ -175,7 +175,7 @@ impl SchemeBlock for DiskScheme {
|
||||
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_length()?;
|
||||
stat.st_blksize = disk.block_size();
|
||||
Ok(Some(0))
|
||||
}
|
||||
Handle::Partition(disk_id, part_num) => {
|
||||
@@ -190,8 +190,8 @@ impl SchemeBlock for DiskScheme {
|
||||
};
|
||||
|
||||
stat.st_mode = MODE_FILE; // TODO: Block device?
|
||||
stat.st_size = size * u64::from(disk.block_length()?);
|
||||
stat.st_blksize = disk.block_length()?;
|
||||
stat.st_size = size * u64::from(disk.block_size());
|
||||
stat.st_blksize = disk.block_size();
|
||||
stat.st_blocks = size;
|
||||
Ok(Some(0))
|
||||
}
|
||||
@@ -263,32 +263,13 @@ impl SchemeBlock for DiskScheme {
|
||||
}
|
||||
Handle::Disk(number) => {
|
||||
let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?;
|
||||
let blk_len = disk.block_length()?;
|
||||
disk.read(offset / u64::from(blk_len), buf)
|
||||
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 blksize = disk.block_length()?;
|
||||
|
||||
// validate that we're actually reading within the bounds of the partition
|
||||
let rel_block = offset / u64::from(blksize);
|
||||
|
||||
let abs_block = {
|
||||
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))?;
|
||||
|
||||
let abs_block = partition.start_lba + rel_block;
|
||||
// TODO: This shouldn't return EOVERFLOW?
|
||||
if rel_block >= partition.size {
|
||||
return Err(Error::new(EOVERFLOW));
|
||||
}
|
||||
abs_block
|
||||
};
|
||||
|
||||
disk.read(abs_block, buf)
|
||||
let block = offset / u64::from(disk.block_size());
|
||||
disk.read(Some(part_num as usize), block, buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -304,31 +285,13 @@ impl SchemeBlock for DiskScheme {
|
||||
Handle::List(_) => Err(Error::new(EBADF)),
|
||||
Handle::Disk(number) => {
|
||||
let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?;
|
||||
let blk_len = disk.block_length()?;
|
||||
disk.write(offset / u64::from(blk_len), buf)
|
||||
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 blksize = disk.block_length()?;
|
||||
|
||||
// validate that we're actually reading within the bounds of the partition
|
||||
let rel_block = offset / u64::from(blksize);
|
||||
|
||||
let abs_block = {
|
||||
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))?;
|
||||
|
||||
let abs_block = partition.start_lba + rel_block;
|
||||
if rel_block >= partition.size {
|
||||
return Err(Error::new(EOVERFLOW));
|
||||
}
|
||||
abs_block
|
||||
};
|
||||
|
||||
disk.write(abs_block, buf)
|
||||
let block = offset / u64::from(disk.block_size());
|
||||
disk.write(Some(part_num as usize), block, buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -351,7 +314,7 @@ impl SchemeBlock for DiskScheme {
|
||||
.get(part_num as usize)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.size;
|
||||
u64::from(disk.block_length()?) * block_count
|
||||
u64::from(disk.block_size()) * block_count
|
||||
}
|
||||
},
|
||||
))
|
||||
|
||||
@@ -5,8 +5,8 @@ use std::str;
|
||||
use driver_block::{Disk, DiskWrapper};
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
use syscall::{
|
||||
Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, MODE_FILE,
|
||||
O_DIRECTORY, O_STAT,
|
||||
Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, MODE_DIR, MODE_FILE, O_DIRECTORY,
|
||||
O_STAT,
|
||||
};
|
||||
|
||||
use redox_scheme::{CallerCtx, OpenResult, SchemeBlock};
|
||||
@@ -19,7 +19,7 @@ enum Handle {
|
||||
|
||||
pub struct DiskScheme {
|
||||
scheme_name: String,
|
||||
disks: Box<[DiskWrapper]>,
|
||||
disks: Box<[DiskWrapper<Box<dyn Disk>>]>,
|
||||
handles: BTreeMap<usize, Handle>,
|
||||
next_id: usize,
|
||||
}
|
||||
@@ -164,7 +164,7 @@ impl SchemeBlock for DiskScheme {
|
||||
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_length()?;
|
||||
stat.st_blksize = disk.block_size();
|
||||
Ok(Some(0))
|
||||
}
|
||||
Handle::Partition(disk_id, part_num) => {
|
||||
@@ -179,8 +179,8 @@ impl SchemeBlock for DiskScheme {
|
||||
};
|
||||
|
||||
stat.st_mode = MODE_FILE; // TODO: Block device?
|
||||
stat.st_size = size * u64::from(disk.block_length()?);
|
||||
stat.st_blksize = disk.block_length()?;
|
||||
stat.st_size = size * u64::from(disk.block_size());
|
||||
stat.st_blksize = disk.block_size();
|
||||
stat.st_blocks = size;
|
||||
Ok(Some(0))
|
||||
}
|
||||
@@ -251,31 +251,13 @@ impl SchemeBlock for DiskScheme {
|
||||
}
|
||||
Handle::Disk(number) => {
|
||||
let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?;
|
||||
let blk_len = disk.block_length()?;
|
||||
disk.read(offset / u64::from(blk_len), buf)
|
||||
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 blksize = disk.block_length()?;
|
||||
|
||||
// validate that we're actually reading within the bounds of the partition
|
||||
let rel_block = offset / u64::from(blksize);
|
||||
|
||||
let abs_block = {
|
||||
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))?;
|
||||
|
||||
let abs_block = partition.start_lba + rel_block;
|
||||
if rel_block >= partition.size {
|
||||
return Err(Error::new(EOVERFLOW));
|
||||
}
|
||||
abs_block
|
||||
};
|
||||
|
||||
disk.read(abs_block, buf)
|
||||
let block = offset / u64::from(disk.block_size());
|
||||
disk.read(Some(part_num as usize), block, buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -285,31 +267,13 @@ impl SchemeBlock for DiskScheme {
|
||||
Handle::List(_) => Err(Error::new(EBADF)),
|
||||
Handle::Disk(number) => {
|
||||
let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?;
|
||||
let blk_len = disk.block_length()?;
|
||||
disk.write(offset / u64::from(blk_len), buf)
|
||||
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 blksize = disk.block_length()?;
|
||||
|
||||
// validate that we're actually reading within the bounds of the partition
|
||||
let rel_block = offset / u64::from(blksize as u64);
|
||||
|
||||
let abs_block = {
|
||||
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))?;
|
||||
|
||||
let abs_block = partition.start_lba + rel_block;
|
||||
if rel_block >= partition.size {
|
||||
return Err(Error::new(EOVERFLOW));
|
||||
}
|
||||
abs_block
|
||||
};
|
||||
|
||||
disk.write(abs_block, buf)
|
||||
let block = offset / u64::from(disk.block_size());
|
||||
disk.write(Some(part_num as usize), block, buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -331,7 +295,7 @@ impl SchemeBlock for DiskScheme {
|
||||
.get(part_num as usize)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.size;
|
||||
Ok(Some(u64::from(disk.block_length()?) * block_count))
|
||||
Ok(Some(u64::from(disk.block_size()) * block_count))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -733,11 +733,11 @@ impl SdHostCtrl {
|
||||
}
|
||||
|
||||
impl Disk for SdHostCtrl {
|
||||
fn id(&self) -> usize {
|
||||
0xdead_dead
|
||||
fn block_size(&self) -> u32 {
|
||||
512
|
||||
}
|
||||
|
||||
fn size(&mut self) -> u64 {
|
||||
fn size(&self) -> u64 {
|
||||
//assert 512MiB
|
||||
self.size
|
||||
}
|
||||
@@ -777,8 +777,4 @@ impl Disk for SdHostCtrl {
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
fn block_length(&mut self) -> Result<u32> {
|
||||
Ok(512)
|
||||
}
|
||||
}
|
||||
|
||||
+111
-48
@@ -3,18 +3,16 @@ use std::io::Error;
|
||||
use std::io::{self, Read, Seek, SeekFrom};
|
||||
|
||||
use partitionlib::{LogicalBlockSize, PartitionTable};
|
||||
use syscall::{EBADF, EOVERFLOW};
|
||||
|
||||
/// 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.
|
||||
/// The buffer must be large enough to hold `blksize` of data.
|
||||
/// `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],
|
||||
block_bytes: &mut [u8],
|
||||
mut read_fn: impl FnMut(u64, &mut [u8]) -> Result<(), Error>,
|
||||
) -> Result<usize, Error> {
|
||||
// TODO: Yield sometimes, perhaps after a few blocks or something.
|
||||
@@ -32,6 +30,9 @@ pub fn block_read(
|
||||
let blk_size = usize::try_from(blksize).expect("blksize larger than usize");
|
||||
let mut total_read = 0;
|
||||
|
||||
let mut block_bytes = [0u8; 4096];
|
||||
let block_bytes = &mut block_bytes[..blk_size];
|
||||
|
||||
while curr_buf.len() > 0 {
|
||||
// TODO: Async/await? I mean, shouldn't AHCI be async?
|
||||
|
||||
@@ -53,32 +54,49 @@ pub fn block_read(
|
||||
}
|
||||
|
||||
pub trait Disk {
|
||||
fn id(&self) -> usize;
|
||||
fn block_length(&mut self) -> syscall::error::Result<u32>;
|
||||
fn size(&mut self) -> u64;
|
||||
fn block_size(&self) -> u32;
|
||||
fn size(&self) -> u64;
|
||||
|
||||
fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result<Option<usize>>;
|
||||
fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result<Option<usize>>;
|
||||
}
|
||||
|
||||
pub struct DiskWrapper {
|
||||
pub disk: Box<dyn Disk>,
|
||||
impl<T: Disk + ?Sized> Disk for Box<T> {
|
||||
fn block_size(&self) -> u32 {
|
||||
(**self).block_size()
|
||||
}
|
||||
|
||||
fn size(&self) -> u64 {
|
||||
(**self).size()
|
||||
}
|
||||
|
||||
fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result<Option<usize>> {
|
||||
(**self).read(block, buffer)
|
||||
}
|
||||
|
||||
fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result<Option<usize>> {
|
||||
(**self).write(block, buffer)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DiskWrapper<T> {
|
||||
pub disk: T,
|
||||
pub pt: Option<PartitionTable>,
|
||||
}
|
||||
|
||||
impl DiskWrapper {
|
||||
fn pt(disk: &mut dyn Disk) -> Option<PartitionTable> {
|
||||
let bs = match disk.block_length() {
|
||||
Ok(512) => LogicalBlockSize::Lb512,
|
||||
impl<T: Disk> DiskWrapper<T> {
|
||||
pub fn pt(disk: &mut T) -> Option<PartitionTable> {
|
||||
let bs = match disk.block_size() {
|
||||
512 => LogicalBlockSize::Lb512,
|
||||
4096 => LogicalBlockSize::Lb4096,
|
||||
_ => return None,
|
||||
};
|
||||
struct Device<'a, 'b> {
|
||||
struct Device<'a> {
|
||||
disk: &'a mut dyn Disk,
|
||||
offset: u64,
|
||||
block_bytes: &'b mut [u8],
|
||||
}
|
||||
|
||||
impl<'a, 'b> Seek for Device<'a, 'b> {
|
||||
impl<'a> Seek for Device<'a> {
|
||||
fn seek(&mut self, from: SeekFrom) -> io::Result<u64> {
|
||||
let size = i64::try_from(self.disk.size()).or(Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
@@ -97,12 +115,9 @@ impl DiskWrapper {
|
||||
}
|
||||
}
|
||||
// TODO: Perhaps this impl should be used in the rest of the scheme.
|
||||
impl<'a, 'b> Read for Device<'a, 'b> {
|
||||
impl<'a> Read for Device<'a> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let blksize = self
|
||||
.disk
|
||||
.block_length()
|
||||
.map_err(|err| io::Error::from_raw_os_error(err.errno))?;
|
||||
let blksize = self.disk.block_size();
|
||||
let size_in_blocks = self.disk.size() / u64::from(blksize);
|
||||
|
||||
let disk = &mut self.disk;
|
||||
@@ -115,7 +130,6 @@ impl DiskWrapper {
|
||||
match disk.read(block, block_bytes) {
|
||||
Ok(Some(bytes)) => {
|
||||
assert_eq!(bytes, block_bytes.len());
|
||||
assert_eq!(bytes, blksize as usize);
|
||||
return Ok(());
|
||||
}
|
||||
Ok(None) => {
|
||||
@@ -126,45 +140,94 @@ impl DiskWrapper {
|
||||
}
|
||||
}
|
||||
};
|
||||
let bytes_read =
|
||||
block_read(self.offset, blksize, buf, self.block_bytes, read_block)?;
|
||||
let bytes_read = block_read(self.offset, blksize, buf, read_block)?;
|
||||
|
||||
self.offset += bytes_read as u64;
|
||||
Ok(bytes_read)
|
||||
}
|
||||
}
|
||||
|
||||
let mut block_bytes = [0u8; 4096];
|
||||
|
||||
partitionlib::get_partitions(
|
||||
&mut Device {
|
||||
disk,
|
||||
offset: 0,
|
||||
block_bytes: &mut block_bytes[..bs.into()],
|
||||
},
|
||||
bs,
|
||||
)
|
||||
.ok()
|
||||
.flatten()
|
||||
partitionlib::get_partitions(&mut Device { disk, offset: 0 }, bs)
|
||||
.ok()
|
||||
.flatten()
|
||||
}
|
||||
|
||||
pub fn new(mut disk: Box<dyn Disk>) -> Self {
|
||||
pub fn new(mut disk: T) -> Self {
|
||||
Self {
|
||||
pt: Self::pt(&mut *disk),
|
||||
pt: Self::pt(&mut disk),
|
||||
disk,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for DiskWrapper {
|
||||
type Target = dyn Disk;
|
||||
pub fn disk(&self) -> &T {
|
||||
&self.disk
|
||||
}
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&*self.disk
|
||||
}
|
||||
}
|
||||
impl std::ops::DerefMut for DiskWrapper {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut *self.disk
|
||||
pub fn disk_mut(&mut self) -> &mut T {
|
||||
&mut self.disk
|
||||
}
|
||||
|
||||
pub fn block_size(&self) -> u32 {
|
||||
self.disk.block_size()
|
||||
}
|
||||
|
||||
pub fn size(&self) -> u64 {
|
||||
self.disk.size()
|
||||
}
|
||||
|
||||
pub fn read(
|
||||
&mut self,
|
||||
part_num: Option<usize>,
|
||||
block: u64,
|
||||
buf: &mut [u8],
|
||||
) -> syscall::Result<Option<usize>> {
|
||||
if let Some(part_num) = part_num {
|
||||
let part = self
|
||||
.pt
|
||||
.as_ref()
|
||||
.ok_or(syscall::Error::new(EBADF))?
|
||||
.partitions
|
||||
.get(part_num)
|
||||
.ok_or(syscall::Error::new(EBADF))?;
|
||||
|
||||
let block_size = u64::from(self.block_size());
|
||||
if block >= part.size / block_size {
|
||||
return Err(syscall::Error::new(EOVERFLOW));
|
||||
}
|
||||
|
||||
let abs_block = part.start_lba + block;
|
||||
|
||||
self.disk.read(abs_block, buf)
|
||||
} else {
|
||||
self.disk.read(block, buf)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(
|
||||
&mut self,
|
||||
part_num: Option<usize>,
|
||||
block: u64,
|
||||
buf: &[u8],
|
||||
) -> syscall::Result<Option<usize>> {
|
||||
if let Some(part_num) = part_num {
|
||||
let part = self
|
||||
.pt
|
||||
.as_ref()
|
||||
.ok_or(syscall::Error::new(EBADF))?
|
||||
.partitions
|
||||
.get(part_num)
|
||||
.ok_or(syscall::Error::new(EBADF))?;
|
||||
|
||||
let block_size = u64::from(self.block_size());
|
||||
if block >= part.size / block_size {
|
||||
return Err(syscall::Error::new(EOVERFLOW));
|
||||
}
|
||||
|
||||
let abs_block = part.start_lba + block;
|
||||
|
||||
self.disk.write(abs_block, buf)
|
||||
} else {
|
||||
self.disk.write(block, buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,11 +169,11 @@ pub struct AtaDisk {
|
||||
}
|
||||
|
||||
impl Disk for AtaDisk {
|
||||
fn id(&self) -> usize {
|
||||
self.chan_i << 1 | self.dev as usize
|
||||
fn block_size(&self) -> u32 {
|
||||
512
|
||||
}
|
||||
|
||||
fn size(&mut self) -> u64 {
|
||||
fn size(&self) -> u64 {
|
||||
self.size
|
||||
}
|
||||
|
||||
@@ -464,8 +464,4 @@ impl Disk for AtaDisk {
|
||||
|
||||
Ok(Some(count))
|
||||
}
|
||||
|
||||
fn block_length(&mut self) -> Result<u32> {
|
||||
Ok(512)
|
||||
}
|
||||
}
|
||||
|
||||
+15
-51
@@ -6,8 +6,8 @@ use std::sync::{Arc, Mutex};
|
||||
use driver_block::{Disk, DiskWrapper};
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
use syscall::{
|
||||
Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, MODE_FILE,
|
||||
O_DIRECTORY, O_STAT,
|
||||
Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, MODE_DIR, MODE_FILE, O_DIRECTORY,
|
||||
O_STAT,
|
||||
};
|
||||
|
||||
use crate::ide::Channel;
|
||||
@@ -22,7 +22,7 @@ enum Handle {
|
||||
pub struct DiskScheme {
|
||||
scheme_name: String,
|
||||
chans: Box<[Arc<Mutex<Channel>>]>,
|
||||
disks: Box<[DiskWrapper]>,
|
||||
disks: Box<[DiskWrapper<Box<dyn Disk>>]>,
|
||||
handles: BTreeMap<usize, Handle>,
|
||||
next_id: usize,
|
||||
}
|
||||
@@ -178,7 +178,7 @@ impl SchemeBlock for DiskScheme {
|
||||
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_length()?;
|
||||
stat.st_blksize = disk.block_size();
|
||||
Ok(Some(0))
|
||||
}
|
||||
Handle::Partition(disk_id, part_num) => {
|
||||
@@ -193,8 +193,8 @@ impl SchemeBlock for DiskScheme {
|
||||
};
|
||||
|
||||
stat.st_mode = MODE_FILE; // TODO: Block device?
|
||||
stat.st_size = size * u64::from(disk.block_length()?);
|
||||
stat.st_blksize = disk.block_length()?;
|
||||
stat.st_size = size * u64::from(disk.block_size());
|
||||
stat.st_blksize = disk.block_size();
|
||||
stat.st_blocks = size;
|
||||
Ok(Some(0))
|
||||
}
|
||||
@@ -265,31 +265,13 @@ impl SchemeBlock for DiskScheme {
|
||||
}
|
||||
Handle::Disk(number) => {
|
||||
let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?;
|
||||
let blk_len = disk.block_length()?;
|
||||
disk.read(offset / u64::from(blk_len), buf)
|
||||
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 blksize = disk.block_length()?;
|
||||
|
||||
// validate that we're actually reading within the bounds of the partition
|
||||
let rel_block = offset / u64::from(blksize);
|
||||
|
||||
let abs_block = {
|
||||
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))?;
|
||||
|
||||
let abs_block = partition.start_lba + rel_block;
|
||||
if rel_block >= partition.size {
|
||||
return Err(Error::new(EOVERFLOW));
|
||||
}
|
||||
abs_block
|
||||
};
|
||||
|
||||
disk.read(abs_block, buf)
|
||||
let block = offset / u64::from(disk.block_size());
|
||||
disk.read(Some(part_num as usize), block, buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -299,31 +281,13 @@ impl SchemeBlock for DiskScheme {
|
||||
Handle::List(_) => Err(Error::new(EBADF)),
|
||||
Handle::Disk(number) => {
|
||||
let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?;
|
||||
let blk_len = disk.block_length()?;
|
||||
disk.write(offset / u64::from(blk_len), buf)
|
||||
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 blksize = disk.block_length()?;
|
||||
|
||||
// validate that we're actually reading within the bounds of the partition
|
||||
let rel_block = offset / u64::from(blksize as u64);
|
||||
|
||||
let abs_block = {
|
||||
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))?;
|
||||
|
||||
let abs_block = partition.start_lba + rel_block;
|
||||
if rel_block >= partition.size {
|
||||
return Err(Error::new(EOVERFLOW));
|
||||
}
|
||||
abs_block
|
||||
};
|
||||
|
||||
disk.write(abs_block, buf)
|
||||
let block = offset / u64::from(disk.block_size());
|
||||
disk.write(Some(part_num as usize), block, buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -345,7 +309,7 @@ impl SchemeBlock for DiskScheme {
|
||||
.get(part_num as usize)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.size;
|
||||
Ok(Some(u64::from(disk.block_length()?) * block_count))
|
||||
Ok(Some(u64::from(disk.block_size()) * block_count))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ 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"
|
||||
partitionlib = { path = "../partitionlib" }
|
||||
smallvec = "1"
|
||||
|
||||
common = { path = "../../common" }
|
||||
|
||||
@@ -170,7 +170,7 @@ pub struct NvmeRegs {
|
||||
cmbsz: Mmio<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct NvmeNamespace {
|
||||
pub id: u32,
|
||||
pub blocks: u64,
|
||||
@@ -641,8 +641,7 @@ impl Nvme {
|
||||
|
||||
fn namespace_rw(
|
||||
&self,
|
||||
namespace: &NvmeNamespace,
|
||||
nsid: u32,
|
||||
namespace: NvmeNamespace,
|
||||
lba: u64,
|
||||
blocks_1: u16,
|
||||
write: bool,
|
||||
@@ -666,9 +665,9 @@ impl Nvme {
|
||||
let mut cmd = NvmeCmd::default();
|
||||
let comp = self.submit_and_complete_command(1, |cid| {
|
||||
cmd = if write {
|
||||
NvmeCmd::io_write(cid, nsid, lba, blocks_1, ptr0, ptr1)
|
||||
NvmeCmd::io_write(cid, namespace.id, lba, blocks_1, ptr0, ptr1)
|
||||
} else {
|
||||
NvmeCmd::io_read(cid, nsid, lba, blocks_1, ptr0, ptr1)
|
||||
NvmeCmd::io_read(cid, namespace.id, lba, blocks_1, ptr0, ptr1)
|
||||
};
|
||||
cmd.clone()
|
||||
});
|
||||
@@ -683,8 +682,7 @@ impl Nvme {
|
||||
|
||||
pub fn namespace_read(
|
||||
&self,
|
||||
namespace: &NvmeNamespace,
|
||||
nsid: u32,
|
||||
namespace: NvmeNamespace,
|
||||
mut lba: u64,
|
||||
buf: &mut [u8],
|
||||
) -> Result<Option<usize>> {
|
||||
@@ -698,7 +696,7 @@ impl Nvme {
|
||||
assert!(blocks > 0);
|
||||
assert!(blocks <= 0x1_0000);
|
||||
|
||||
self.namespace_rw(namespace, nsid, lba, (blocks - 1) as u16, false)?;
|
||||
self.namespace_rw(namespace, lba, (blocks - 1) as u16, false)?;
|
||||
|
||||
chunk.copy_from_slice(&buffer_guard[..chunk.len()]);
|
||||
|
||||
@@ -710,8 +708,7 @@ impl Nvme {
|
||||
|
||||
pub fn namespace_write(
|
||||
&self,
|
||||
namespace: &NvmeNamespace,
|
||||
nsid: u32,
|
||||
namespace: NvmeNamespace,
|
||||
mut lba: u64,
|
||||
buf: &[u8],
|
||||
) -> Result<Option<usize>> {
|
||||
@@ -727,7 +724,7 @@ impl Nvme {
|
||||
|
||||
buffer_guard[..chunk.len()].copy_from_slice(chunk);
|
||||
|
||||
self.namespace_rw(namespace, nsid, lba, (blocks - 1) as u16, true)?;
|
||||
self.namespace_rw(namespace, lba, (blocks - 1) as u16, true)?;
|
||||
|
||||
lba += blocks as u64;
|
||||
}
|
||||
|
||||
+34
-173
@@ -1,144 +1,48 @@
|
||||
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, DiskWrapper};
|
||||
use redox_scheme::{CallerCtx, OpenResult, SchemeBlock};
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
use syscall::{
|
||||
Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, MODE_FILE,
|
||||
O_DIRECTORY, O_STAT,
|
||||
Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, MODE_DIR, MODE_FILE, O_DIRECTORY,
|
||||
O_STAT,
|
||||
};
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
pub struct DiskWrapper {
|
||||
inner: NvmeNamespace,
|
||||
pt: Option<PartitionTable>,
|
||||
}
|
||||
struct NvmeDisk(Arc<Nvme>, NvmeNamespace);
|
||||
|
||||
impl AsRef<NvmeNamespace> for DiskWrapper {
|
||||
fn as_ref(&self) -> &NvmeNamespace {
|
||||
&self.inner
|
||||
impl Disk for NvmeDisk {
|
||||
fn block_size(&self) -> u32 {
|
||||
self.1.block_size.try_into().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl DiskWrapper {
|
||||
fn pt(disk: &mut NvmeNamespace, nvme: &Nvme) -> Option<PartitionTable> {
|
||||
let bs = match disk.block_size {
|
||||
512 => LogicalBlockSize::Lb512,
|
||||
4096 => LogicalBlockSize::Lb4096,
|
||||
_ => return None,
|
||||
};
|
||||
struct Device<'a, 'b> {
|
||||
disk: &'a mut NvmeNamespace,
|
||||
nvme: &'a Nvme,
|
||||
offset: u64,
|
||||
block_bytes: &'b mut [u8],
|
||||
}
|
||||
|
||||
impl<'a, 'b> Seek for Device<'a, 'b> {
|
||||
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, 'b> Read for Device<'a, 'b> {
|
||||
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 = &mut 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, disk.id, 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,
|
||||
self.block_bytes,
|
||||
read_block,
|
||||
)?;
|
||||
self.offset += bytes_read as u64;
|
||||
Ok(bytes_read)
|
||||
}
|
||||
}
|
||||
|
||||
let mut block_bytes = [0u8; 4096];
|
||||
|
||||
partitionlib::get_partitions(
|
||||
&mut Device {
|
||||
disk,
|
||||
nvme,
|
||||
offset: 0,
|
||||
block_bytes: &mut block_bytes[..bs.into()],
|
||||
},
|
||||
bs,
|
||||
)
|
||||
.ok()
|
||||
.flatten()
|
||||
fn size(&self) -> u64 {
|
||||
self.1.blocks * self.1.block_size
|
||||
}
|
||||
fn new(mut inner: NvmeNamespace, nvme: &Nvme) -> Self {
|
||||
Self {
|
||||
pt: Self::pt(&mut inner, nvme),
|
||||
inner,
|
||||
}
|
||||
|
||||
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 DiskScheme {
|
||||
scheme_name: String,
|
||||
nvme: Arc<Nvme>,
|
||||
disks: BTreeMap<u32, DiskWrapper>,
|
||||
disks: BTreeMap<u32, DiskWrapper<NvmeDisk>>,
|
||||
handles: BTreeMap<usize, Handle>,
|
||||
next_id: usize,
|
||||
}
|
||||
@@ -153,9 +57,8 @@ impl DiskScheme {
|
||||
scheme_name,
|
||||
disks: disks
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, DiskWrapper::new(v, &nvme)))
|
||||
.map(|(k, ns)| (k, DiskWrapper::new(NvmeDisk(nvme.clone(), ns))))
|
||||
.collect(),
|
||||
nvme,
|
||||
handles: BTreeMap::new(),
|
||||
next_id: 0,
|
||||
}
|
||||
@@ -280,13 +183,9 @@ impl SchemeBlock for DiskScheme {
|
||||
Handle::Disk(number) => {
|
||||
let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?;
|
||||
stat.st_mode = MODE_FILE;
|
||||
stat.st_blocks = disk.as_ref().blocks;
|
||||
stat.st_blksize = disk
|
||||
.as_ref()
|
||||
.block_size
|
||||
.try_into()
|
||||
.expect("Unreasonable block size of over 2^32 bytes");
|
||||
stat.st_size = disk.as_ref().blocks * disk.as_ref().block_size;
|
||||
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) => {
|
||||
@@ -299,13 +198,9 @@ impl SchemeBlock for DiskScheme {
|
||||
.get(part_num as usize)
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
stat.st_mode = MODE_FILE;
|
||||
stat.st_size = part.size * disk.as_ref().block_size;
|
||||
stat.st_size = part.size * u64::from(disk.block_size());
|
||||
stat.st_blocks = part.size;
|
||||
stat.st_blksize = disk
|
||||
.as_ref()
|
||||
.block_size
|
||||
.try_into()
|
||||
.expect("Unreasonable block size of over 2^32 bytes");
|
||||
stat.st_blksize = disk.block_size();
|
||||
Ok(Some(0))
|
||||
}
|
||||
}
|
||||
@@ -375,30 +270,13 @@ impl SchemeBlock for DiskScheme {
|
||||
}
|
||||
Handle::Disk(number) => {
|
||||
let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?;
|
||||
let block_size = disk.as_ref().block_size;
|
||||
self.nvme
|
||||
.namespace_read(disk.as_ref(), disk.as_ref().id, offset / block_size, buf)
|
||||
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 part = disk
|
||||
.pt
|
||||
.as_ref()
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.partitions
|
||||
.get(part_num as usize)
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
|
||||
let block_size = disk.as_ref().block_size;
|
||||
let rel_block = offset / block_size;
|
||||
if rel_block >= part.size {
|
||||
return Err(Error::new(EOVERFLOW));
|
||||
}
|
||||
|
||||
let abs_block = part.start_lba + rel_block;
|
||||
|
||||
self.nvme
|
||||
.namespace_read(disk.as_ref(), disk.as_ref().id, abs_block, buf)
|
||||
let block = offset / u64::from(disk.block_size());
|
||||
disk.read(Some(part_num as usize), block, buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -414,30 +292,13 @@ impl SchemeBlock for DiskScheme {
|
||||
Handle::List(_) => Err(Error::new(EBADF)),
|
||||
Handle::Disk(number) => {
|
||||
let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?;
|
||||
let block_size = disk.as_ref().block_size;
|
||||
self.nvme
|
||||
.namespace_write(disk.as_ref(), disk.as_ref().id, offset / block_size, buf)
|
||||
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 part = disk
|
||||
.pt
|
||||
.as_ref()
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.partitions
|
||||
.get(part_num as usize)
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
|
||||
let block_size = disk.as_ref().block_size;
|
||||
let rel_block = offset / block_size;
|
||||
if rel_block >= part.size {
|
||||
return Err(Error::new(EOVERFLOW));
|
||||
}
|
||||
|
||||
let abs_block = part.start_lba + rel_block;
|
||||
|
||||
self.nvme
|
||||
.namespace_write(disk.as_ref(), disk.as_ref().id, abs_block, buf)
|
||||
let block = offset / u64::from(disk.block_size());
|
||||
disk.write(Some(part_num as usize), block, buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -448,7 +309,7 @@ impl SchemeBlock for DiskScheme {
|
||||
Handle::List(ref handle) => handle.len() as u64,
|
||||
Handle::Disk(number) => {
|
||||
let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?;
|
||||
disk.as_ref().blocks * disk.as_ref().block_size
|
||||
disk.size()
|
||||
}
|
||||
Handle::Partition(disk_num, part_num) => {
|
||||
let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?;
|
||||
@@ -460,7 +321,7 @@ impl SchemeBlock for DiskScheme {
|
||||
.get(part_num as usize)
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
|
||||
part.size * disk.as_ref().block_size
|
||||
part.size * u64::from(disk.block_size())
|
||||
}
|
||||
},
|
||||
))
|
||||
|
||||
@@ -15,7 +15,6 @@ spin = "*"
|
||||
redox-daemon = "0.1"
|
||||
redox_syscall = { version = "0.5", features = ["std"] }
|
||||
redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" }
|
||||
partitionlib = { path = "../partitionlib" }
|
||||
|
||||
common = { path = "../../common" }
|
||||
driver-block = { path = "../driver-block" }
|
||||
|
||||
@@ -1,14 +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 partitionlib::PartitionTable;
|
||||
use driver_block::DiskWrapper;
|
||||
|
||||
use redox_scheme::CallerCtx;
|
||||
use redox_scheme::OpenResult;
|
||||
@@ -90,6 +86,39 @@ impl BlkExtension for Queue<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
struct VirtioDisk<'a> {
|
||||
queue: Arc<Queue<'a>>,
|
||||
cfg: BlockDeviceConfig,
|
||||
}
|
||||
|
||||
impl<'a> VirtioDisk<'a> {
|
||||
pub fn new(queue: Arc<Queue<'a>>, cfg: BlockDeviceConfig) -> Self {
|
||||
Self { queue, cfg }
|
||||
}
|
||||
}
|
||||
|
||||
impl driver_block::Disk for VirtioDisk<'_> {
|
||||
fn block_size(&self) -> u32 {
|
||||
self.cfg.block_size()
|
||||
}
|
||||
|
||||
fn size(&self) -> u64 {
|
||||
self.cfg.capacity() * u64::from(self.cfg.block_size())
|
||||
}
|
||||
|
||||
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>> {
|
||||
Ok(Some(futures::executor::block_on(
|
||||
self.queue.write(block, buffer),
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Handle {
|
||||
Partition {
|
||||
/// Partition Number
|
||||
@@ -104,102 +133,18 @@ pub enum Handle {
|
||||
}
|
||||
|
||||
pub struct DiskScheme<'a> {
|
||||
queue: Arc<Queue<'a>>,
|
||||
disk: DiskWrapper<VirtioDisk<'a>>,
|
||||
next_id: usize,
|
||||
cfg: BlockDeviceConfig,
|
||||
handles: BTreeMap<usize, Handle>,
|
||||
part_table: Option<PartitionTable>,
|
||||
}
|
||||
|
||||
impl<'a> DiskScheme<'a> {
|
||||
pub fn new(queue: Arc<Queue<'a>>, cfg: BlockDeviceConfig) -> Self {
|
||||
let mut this = Self {
|
||||
queue,
|
||||
Self {
|
||||
disk: DiskWrapper::new(VirtioDisk::new(queue, cfg)),
|
||||
next_id: 0,
|
||||
cfg,
|
||||
handles: BTreeMap::new(),
|
||||
part_table: None,
|
||||
};
|
||||
|
||||
struct VirtioShim<'a, 'b> {
|
||||
scheme: &'b DiskScheme<'a>,
|
||||
offset: u64,
|
||||
block_bytes: &'b mut [u8],
|
||||
}
|
||||
|
||||
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, self.block_bytes, 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,
|
||||
block_bytes: &mut [0u8; 4096],
|
||||
};
|
||||
|
||||
//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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +165,7 @@ impl<'a> SchemeBlock for DiskScheme<'a> {
|
||||
// to the namespace id).
|
||||
write!(list, "{}\n", 0).unwrap();
|
||||
|
||||
if let Some(part_table) = &self.part_table {
|
||||
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();
|
||||
}
|
||||
@@ -251,7 +196,7 @@ impl<'a> SchemeBlock for DiskScheme<'a> {
|
||||
let part_num_str = &path_str[p_pos + 1..];
|
||||
let part_num = part_num_str.parse::<u32>().unwrap();
|
||||
|
||||
let part_table = self.part_table.as_ref().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;
|
||||
@@ -284,45 +229,25 @@ impl<'a> SchemeBlock for DiskScheme<'a> {
|
||||
offset: u64,
|
||||
_fcntl_flags: u32,
|
||||
) -> syscall::Result<Option<usize>> {
|
||||
Ok(Some(
|
||||
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]);
|
||||
count
|
||||
}
|
||||
|
||||
Handle::Partition { number } => {
|
||||
let part_table = self.part_table.as_ref().unwrap();
|
||||
let part = part_table
|
||||
.partitions
|
||||
.get(number as usize)
|
||||
.ok_or(Error::new(EBADF))?;
|
||||
|
||||
// Get the offset in sectors.
|
||||
let rel_block = offset / BLK_SIZE;
|
||||
// if rel_block >= part.size {
|
||||
// return Err(Error::new(EOVERFLOW));
|
||||
// }
|
||||
|
||||
let abs_block = part.start_lba + rel_block;
|
||||
|
||||
futures::executor::block_on(self.queue.read(abs_block, buf))
|
||||
}
|
||||
|
||||
Handle::Disk => {
|
||||
let block_size = self.cfg.block_size();
|
||||
|
||||
futures::executor::block_on(
|
||||
self.queue.read(offset / u64::from(block_size), buf),
|
||||
)
|
||||
}
|
||||
},
|
||||
))
|
||||
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(
|
||||
@@ -332,18 +257,17 @@ impl<'a> SchemeBlock for DiskScheme<'a> {
|
||||
offset: u64,
|
||||
_fcntl_flags: u32,
|
||||
) -> syscall::Result<Option<usize>> {
|
||||
Ok(Some(
|
||||
match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? {
|
||||
Handle::Disk => {
|
||||
let block_size = self.cfg.block_size();
|
||||
futures::executor::block_on(
|
||||
self.queue.write(offset / u64::from(block_size), buf),
|
||||
)
|
||||
}
|
||||
|
||||
_ => todo!(),
|
||||
},
|
||||
))
|
||||
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<Option<u64>> {
|
||||
@@ -357,7 +281,7 @@ impl<'a> SchemeBlock for DiskScheme<'a> {
|
||||
}
|
||||
|
||||
Handle::Partition { number } => {
|
||||
let part_table = self.part_table.as_ref().unwrap();
|
||||
let part_table = self.disk.pt.as_ref().unwrap();
|
||||
let part = part_table
|
||||
.partitions
|
||||
.get(number as usize)
|
||||
@@ -371,7 +295,7 @@ impl<'a> SchemeBlock for DiskScheme<'a> {
|
||||
len
|
||||
}
|
||||
|
||||
Handle::Disk => self.cfg.capacity() * u64::from(self.cfg.block_size()),
|
||||
Handle::Disk => self.disk.size(),
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user