virtiod: refactoring

Signed-off-by: Anhad Singh <andypython@protonmail.com>
This commit is contained in:
Anhad Singh
2023-06-23 16:18:14 +10:00
parent c176903905
commit 65c4317564
3 changed files with 94 additions and 127 deletions
+18 -15
View File
@@ -3,7 +3,7 @@
use core::ptr::NonNull;
use std::fs::File;
use std::io::{self, ErrorKind};
use std::io;
use std::io::{Read, Write};
use std::ops::{Add, Div, Rem};
use std::os::fd::{AsRawFd, FromRawFd, RawFd};
@@ -375,7 +375,8 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> {
.add(
irq_handle.as_raw_fd(),
move |_| -> Result<Option<usize>, io::Error> {
let isr = isr.get() as usize;
// Read from ISR to acknowledge the interrupt.
let _isr = isr.get() as usize;
let mut inner = queue_copy.inner.lock().unwrap();
let used_head = inner.used.head_index();
@@ -384,18 +385,20 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> {
return Ok(None);
}
let used = inner.used.get_element_at((used_head - 1) as usize);
let mut desc_idx = used.table_index.get();
inner.descriptor_stack.push_back(desc_idx as u16);
loop {
let desc = &inner.descriptor[desc_idx as usize];
if !desc.flags.contains(DescriptorFlags::NEXT) {
break;
}
desc_idx = desc.next.into();
for i in progress_head..used_head {
let used = inner.used.get_element_at(i as usize);
let mut desc_idx = used.table_index.get();
inner.descriptor_stack.push_back(desc_idx as u16);
loop {
let desc = &inner.descriptor[desc_idx as usize];
if !desc.flags.contains(DescriptorFlags::NEXT) {
break;
}
desc_idx = desc.next.into();
inner.descriptor_stack.push_back(desc_idx as u16);
}
}
progress_head = used_head;
@@ -405,7 +408,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> {
irq_handle.read(&mut buf)?;
// Acknowledge the interrupt.
// irq_handle.write(&buf)?;
Ok(Some(isr))
Ok(None)
},
)
.unwrap();
@@ -437,7 +440,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> {
let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) };
let mut scheme = scheme::DiskScheme::new(scheme_name, queue, device_space);
let mut scheme = scheme::DiskScheme::new(queue, device_space);
deamon.ready().expect("virtio: failed to deamonize");
+61 -110
View File
@@ -24,6 +24,10 @@ const BLK_SIZE: u64 = 512;
trait BlkExtension {
/// XXX: Reads only one block despite the size of the output buffer. Use [`BlkExtension::read`] instead.
fn read_block(&self, block: u64, block_bytes: &mut [u8]) -> usize;
/// XXX: Reads only one block despite the size of the output buffer. Use [`BlkExtension::write`] instead.
fn write_block(&self, block: u64, block_bytes: &[u8]) -> usize;
fn read(&self, block: u64, block_bytes: &mut [u8]) -> usize {
let sectors = block_bytes.len() / BLK_SIZE as usize;
@@ -31,6 +35,14 @@ trait BlkExtension {
.map(|i| self.read_block(block + i as u64, &mut block_bytes[i * BLK_SIZE as usize..]))
.sum()
}
fn write(&self, block: u64, block_bytes: &[u8]) -> usize {
let sectors = block_bytes.len() / BLK_SIZE as usize;
(0..sectors)
.map(|i| self.write_block(block + i as u64, &block_bytes[i * BLK_SIZE as usize..]))
.sum()
}
}
impl BlkExtension for Queue<'_> {
@@ -64,6 +76,36 @@ impl BlkExtension for Queue<'_> {
size
}
fn write_block(&self, block: u64, block_bytes: &[u8]) -> usize {
let req = syscall::Dma::new(BlockVirtRequest {
ty: BlockRequestTy::Out,
reserved: 0,
sector: block,
})
.unwrap();
let mut result = syscall::Dma::new([0u8; 512]).unwrap();
result.copy_from_slice(&block_bytes[..512]);
let status = syscall::Dma::new(u8::MAX).unwrap();
let chain = ChainBuilder::new()
.chain(Buffer::new(&req).flags(DescriptorFlags::NEXT))
.chain(Buffer::new(&result).flags(DescriptorFlags::NEXT))
.chain(Buffer::new(&status).flags(DescriptorFlags::WRITE_ONLY))
.build();
self.send(chain);
// FIXME: interrupts are for a reason
while *status != 0 {
core::hint::spin_loop();
}
std::thread::yield_now();
block_bytes.len()
}
}
pub enum Handle {
@@ -85,7 +127,6 @@ pub enum Handle {
}
pub struct DiskScheme<'a> {
name: String,
queue: Arc<Queue<'a>>,
next_id: usize,
cfg: &'a mut BlockDeviceConfig,
@@ -94,9 +135,8 @@ pub struct DiskScheme<'a> {
}
impl<'a> DiskScheme<'a> {
pub fn new(name: String, queue: Arc<Queue<'a>>, cfg: &'a mut BlockDeviceConfig) -> Self {
pub fn new(queue: Arc<Queue<'a>>, cfg: &'a mut BlockDeviceConfig) -> Self {
let mut this = Self {
name,
queue,
next_id: 0,
cfg,
@@ -197,10 +237,10 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> {
&mut self,
path: &str,
flags: usize,
uid: u32,
gid: u32,
_uid: u32,
_gid: u32,
) -> syscall::Result<Option<usize>> {
log::info!("virtioo: open: {}", path);
log::info!("virtiod: open: {}", path);
let path_str = path.trim_matches('/');
if path_str.is_empty() {
@@ -264,28 +304,6 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> {
}
}
fn chmod(
&mut self,
path: &str,
mode: u16,
uid: u32,
gid: u32,
) -> syscall::Result<Option<usize>> {
todo!()
}
fn rmdir(&mut self, path: &str, uid: u32, gid: u32) -> syscall::Result<Option<usize>> {
todo!()
}
fn unlink(&mut self, path: &str, uid: u32, gid: u32) -> syscall::Result<Option<usize>> {
todo!()
}
fn dup(&mut self, old_id: usize, buf: &[u8]) -> syscall::Result<Option<usize>> {
todo!()
}
fn read(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result<Option<usize>> {
match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? {
Handle::List {
@@ -323,7 +341,7 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> {
Handle::Disk { ref mut offset } => {
let block_size = self.cfg.block_size();
let count = self.queue.read((*offset as u64) / 512, buf);
let count = self.queue.read((*offset as u64) / block_size as u64, buf);
*offset += count;
Ok(Some(count))
}
@@ -331,8 +349,17 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> {
}
fn write(&mut self, id: usize, buf: &[u8]) -> syscall::Result<Option<usize>> {
// lets assume this worked
Ok(Some(buf.len()))
match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? {
Handle::Disk { ref mut offset } => {
let block_size = self.cfg.block_size();
let count = self.queue.write((*offset as u64) / block_size as u64, buf);
*offset += count;
Ok(Some(count))
}
_ => unimplemented!(),
}
}
fn seek(&mut self, id: usize, pos: isize, whence: usize) -> syscall::Result<Option<isize>> {
@@ -394,91 +421,15 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> {
}
}
fn fchmod(&mut self, id: usize, mode: u16) -> syscall::Result<Option<usize>> {
fn fpath(&mut self, _id: usize, _buf: &mut [u8]) -> syscall::Result<Option<usize>> {
todo!()
}
fn fchown(&mut self, id: usize, uid: u32, gid: u32) -> syscall::Result<Option<usize>> {
fn fstat(&mut self, _id: usize, _stat: &mut syscall::Stat) -> syscall::Result<Option<usize>> {
todo!()
}
fn fcntl(&mut self, id: usize, cmd: usize, arg: usize) -> syscall::Result<Option<usize>> {
todo!()
}
fn fevent(
&mut self,
id: usize,
flags: syscall::EventFlags,
) -> syscall::Result<Option<syscall::EventFlags>> {
todo!()
}
fn fmap_old(&mut self, id: usize, map: &syscall::OldMap) -> syscall::Result<Option<usize>> {
todo!()
}
fn fmap(&mut self, id: usize, map: &syscall::Map) -> syscall::Result<Option<usize>> {
if map.flags.contains(syscall::MapFlags::MAP_FIXED) {
return Err(syscall::Error::new(syscall::EINVAL));
}
self.fmap_old(
id,
&syscall::OldMap {
offset: map.offset,
size: map.size,
flags: map.flags,
},
)
}
fn funmap_old(&mut self, address: usize) -> syscall::Result<Option<usize>> {
todo!()
}
fn funmap(&mut self, address: usize, length: usize) -> syscall::Result<Option<usize>> {
todo!()
}
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result<Option<usize>> {
todo!()
}
fn frename(
&mut self,
id: usize,
path: &str,
uid: u32,
gid: u32,
) -> syscall::Result<Option<usize>> {
todo!()
}
fn fstat(&mut self, id: usize, stat: &mut syscall::Stat) -> syscall::Result<Option<usize>> {
todo!()
}
fn fstatvfs(
&mut self,
id: usize,
stat: &mut syscall::StatVfs,
) -> syscall::Result<Option<usize>> {
todo!()
}
fn fsync(&mut self, id: usize) -> syscall::Result<Option<usize>> {
todo!()
}
fn ftruncate(&mut self, id: usize, len: usize) -> syscall::Result<Option<usize>> {
todo!()
}
fn futimens(
&mut self,
id: usize,
times: &[syscall::TimeSpec],
) -> syscall::Result<Option<usize>> {
fn dup(&mut self, _old_id: usize, _buf: &[u8]) -> Result<Option<usize>> {
todo!()
}
+15 -2
View File
@@ -136,10 +136,23 @@ impl<'a> Queue<'a> {
}
fn alloc_descriptor(&self) -> usize {
if let Some(index) = self.inner.lock().unwrap().descriptor_stack.pop_front() {
let mut inner = self.inner.lock().unwrap();
if let Some(index) = inner.descriptor_stack.pop_front() {
index as usize
} else {
panic!("virtio: descriptor exhaustion");
log::warn!("virtiod: descriptors exhausted, waiting on garabage collector");
drop(inner);
// Wait for the garbage collector thread to release some descriptors.
//
// TODO(andypython): Instead of just yielding, we should have a proper notificiation
// mechanism. I am not aware whats the standard way redox applications
// or drivers implement basically a WaitQueue which you can use to wake
// up a thread. The descripts really should NEVER run out, but if they
// do, have a proper way to handle them.
std::thread::yield_now();
self.alloc_descriptor()
}
}
}