diff --git a/Cargo.lock b/Cargo.lock index 0bc2322768..7f304690ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/storage/ahcid/src/ahci/disk_ata.rs b/storage/ahcid/src/ahci/disk_ata.rs index 2dc2a1f190..bb52a4571d 100644 --- a/storage/ahcid/src/ahci/disk_ata.rs +++ b/storage/ahcid/src/ahci/disk_ata.rs @@ -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 { - Ok(512) - } } diff --git a/storage/ahcid/src/ahci/disk_atapi.rs b/storage/ahcid/src/ahci/disk_atapi.rs index 29ae47996c..b92112c36e 100644 --- a/storage/ahcid/src/ahci/disk_atapi.rs +++ b/storage/ahcid/src/ahci/disk_atapi.rs @@ -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> { // 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> { Err(Error::new(EBADF)) // TODO: Implement writing } - - fn block_length(&mut self) -> Result { - Ok(self.read_capacity()?.1) - } } diff --git a/storage/ahcid/src/scheme.rs b/storage/ahcid/src/scheme.rs index 7ed30f2de1..74dc53067e 100644 --- a/storage/ahcid/src/scheme.rs +++ b/storage/ahcid/src/scheme.rs @@ -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>]>, handles: BTreeMap, 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 } }, )) diff --git a/storage/bcm2835-sdhcid/src/scheme.rs b/storage/bcm2835-sdhcid/src/scheme.rs index 70bf4772e0..dfd7264786 100644 --- a/storage/bcm2835-sdhcid/src/scheme.rs +++ b/storage/bcm2835-sdhcid/src/scheme.rs @@ -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>]>, handles: BTreeMap, 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)) } } } diff --git a/storage/bcm2835-sdhcid/src/sd/mod.rs b/storage/bcm2835-sdhcid/src/sd/mod.rs index 8c718ba105..f8e9ab351b 100644 --- a/storage/bcm2835-sdhcid/src/sd/mod.rs +++ b/storage/bcm2835-sdhcid/src/sd/mod.rs @@ -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 { - Ok(512) - } } diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs index 2d40c69d57..a2910c7b11 100644 --- a/storage/driver-block/src/lib.rs +++ b/storage/driver-block/src/lib.rs @@ -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 { // 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; - 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>; fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result>; } -pub struct DiskWrapper { - pub disk: Box, +impl Disk for Box { + 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> { + (**self).read(block, buffer) + } + + fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result> { + (**self).write(block, buffer) + } +} + +pub struct DiskWrapper { + pub disk: T, pub pt: Option, } -impl DiskWrapper { - fn pt(disk: &mut dyn Disk) -> Option { - let bs = match disk.block_length() { - Ok(512) => LogicalBlockSize::Lb512, +impl DiskWrapper { + pub fn pt(disk: &mut T) -> Option { + 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 { 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 { - 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) -> 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, + block: u64, + buf: &mut [u8], + ) -> syscall::Result> { + 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, + block: u64, + buf: &[u8], + ) -> syscall::Result> { + 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) + } } } diff --git a/storage/ided/src/ide.rs b/storage/ided/src/ide.rs index ad2b771446..9748b46b93 100644 --- a/storage/ided/src/ide.rs +++ b/storage/ided/src/ide.rs @@ -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 { - Ok(512) - } } diff --git a/storage/ided/src/scheme.rs b/storage/ided/src/scheme.rs index ff0a63e58a..f41a227579 100644 --- a/storage/ided/src/scheme.rs +++ b/storage/ided/src/scheme.rs @@ -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>]>, - disks: Box<[DiskWrapper]>, + disks: Box<[DiskWrapper>]>, handles: BTreeMap, 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)) } } } diff --git a/storage/nvmed/Cargo.toml b/storage/nvmed/Cargo.toml index 04cf4bb27c..8a6d1c6663 100644 --- a/storage/nvmed/Cargo.toml +++ b/storage/nvmed/Cargo.toml @@ -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" } diff --git a/storage/nvmed/src/nvme/mod.rs b/storage/nvmed/src/nvme/mod.rs index 127dd5ae9f..93a1c03b9b 100644 --- a/storage/nvmed/src/nvme/mod.rs +++ b/storage/nvmed/src/nvme/mod.rs @@ -170,7 +170,7 @@ pub struct NvmeRegs { cmbsz: Mmio, } -#[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> { @@ -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> { @@ -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; } diff --git a/storage/nvmed/src/scheme.rs b/storage/nvmed/src/scheme.rs index 493a08293b..bd864441dd 100644 --- a/storage/nvmed/src/scheme.rs +++ b/storage/nvmed/src/scheme.rs @@ -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), // entries Disk(u32), // disk num Partition(u32, u32), // disk num, part num } -pub struct DiskWrapper { - inner: NvmeNamespace, - pt: Option, -} +struct NvmeDisk(Arc, NvmeNamespace); -impl AsRef 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 { - 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 { - 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 { - 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> { + 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, - nvme: Arc, - disks: BTreeMap, + disks: BTreeMap>, handles: BTreeMap, 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()) } }, )) diff --git a/storage/virtio-blkd/Cargo.toml b/storage/virtio-blkd/Cargo.toml index de7aba04a1..2b2a663565 100644 --- a/storage/virtio-blkd/Cargo.toml +++ b/storage/virtio-blkd/Cargo.toml @@ -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" } diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index 609f5f5059..974573da51 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -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>, + cfg: BlockDeviceConfig, +} + +impl<'a> VirtioDisk<'a> { + pub fn new(queue: Arc>, 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> { + Ok(Some(futures::executor::block_on( + self.queue.read(block, buffer), + ))) + } + + fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result> { + 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>, + disk: DiskWrapper>, next_id: usize, - cfg: BlockDeviceConfig, handles: BTreeMap, - part_table: Option, } impl<'a> DiskScheme<'a> { pub fn new(queue: Arc>, 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 { - 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 { - 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::().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> { - 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> { - 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> { @@ -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(), }, )) }