From f166968e5755aa8f185ffe1bdbe0c32453349ff0 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Fri, 8 Dec 2023 23:19:12 +0200 Subject: [PATCH] task: better async error handling --- src/device/nvme/error.rs | 15 +++++++++++++++ src/device/nvme/mod.rs | 26 +++++++++----------------- src/device/nvme/queue.rs | 29 +++++++++++++++-------------- src/task/runtime/executor.rs | 6 ++++-- src/task/runtime/task.rs | 27 +++++++++++++++++++++++++-- 5 files changed, 68 insertions(+), 35 deletions(-) create mode 100644 src/device/nvme/error.rs diff --git a/src/device/nvme/error.rs b/src/device/nvme/error.rs new file mode 100644 index 00000000..86553300 --- /dev/null +++ b/src/device/nvme/error.rs @@ -0,0 +1,15 @@ +use abi::error::Error; + +use super::queue::CommandError; + +#[derive(Debug)] +pub enum NvmeError { + MemoryError(Error), + CommandError(CommandError), +} + +impl From for NvmeError { + fn from(value: CommandError) -> Self { + Self::CommandError(value) + } +} diff --git a/src/device/nvme/mod.rs b/src/device/nvme/mod.rs index 67548164..f11928da 100644 --- a/src/device/nvme/mod.rs +++ b/src/device/nvme/mod.rs @@ -29,12 +29,14 @@ use crate::{ use self::{ command::{CreateIoCompletionQueue, CreateIoSubmissionQueue, SetFeatureRequest}, + error::NvmeError, queue::QueuePair, }; use super::bus::pci::{FromPciBus, PciDeviceInfo}; mod command; +mod error; mod queue; register_bitfields! { @@ -120,29 +122,23 @@ impl Regs { } impl NvmeController { - async fn late_init(&'static self) { - // let ioq = QueuePair::new(capacity, sq_doorbell, cq_doorbell).unwrap(); - + async fn late_init(&'static self) -> Result<(), NvmeError> { runtime::spawn(self.poll_task()).expect("Couldn't spawn NVMe poll task"); let admin_q = self.admin_q.get(); // Request a CQ/SQ pair for I/O admin_q .request_no_data(SetFeatureRequest::NumberOfQueues(1, 1)) - .unwrap() - .await - .unwrap(); + .await?; // Allocate the queue let (sq_doorbell, cq_doorbell) = unsafe { self.doorbell_pair(1) }; - let io_q = QueuePair::new(32, sq_doorbell, cq_doorbell).unwrap(); + let io_q = QueuePair::new(32, sq_doorbell, cq_doorbell).map_err(NvmeError::MemoryError)?; // Identify the controller let identify = admin_q - .request(IdentifyControllerRequest { nsid: 0 }) - .unwrap() - .await - .unwrap(); + .request(IdentifyControllerRequest { nsid: 0 })? + .await?; // Create the queue on the device side admin_q @@ -151,9 +147,7 @@ impl NvmeController { size: 32, data: io_q.cq_physical_pointer(), }) - .unwrap() - .await - .unwrap(); + .await?; admin_q .request_no_data(CreateIoSubmissionQueue { id: 1, @@ -161,9 +155,7 @@ impl NvmeController { size: 32, data: io_q.sq_physical_pointer(), }) - .unwrap() - .await - .unwrap(); + .await?; loop {} } diff --git a/src/device/nvme/queue.rs b/src/device/nvme/queue.rs index 7cece0c1..afab4c02 100644 --- a/src/device/nvme/queue.rs +++ b/src/device/nvme/queue.rs @@ -22,7 +22,10 @@ use crate::{ task::runtime::QueueWaker, }; -use super::command::{Command, Request}; +use super::{ + command::{Command, Request}, + error::NvmeError, +}; #[derive(Zeroable, Pod, Clone, Copy, Debug)] #[repr(C)] @@ -338,12 +341,7 @@ impl<'a> QueuePair<'a> { } } - pub fn submit( - &self, - cmd: C, - ranges: &[PhysicalAddress], - set_pending: bool, - ) -> Result { + pub fn submit(&self, cmd: C, ranges: &[PhysicalAddress], set_pending: bool) -> u32 { let mut inner = self.inner.lock(); let mut sqe = SubmissionQueueEntry::zeroed(); @@ -370,24 +368,27 @@ impl<'a> QueuePair<'a> { inner.sq.enqueue(sqe); - Ok(command_id) + command_id } pub fn request_no_data<'r, C: Command>( &'r self, req: C, - ) -> Result> + 'r, Error> + ) -> impl Future> + 'r where 'r: 'a, { - let command_id = self.submit(req, &[], true)?; - Ok(self.wait_for_completion(command_id, ())) + let command_id = self.submit(req, &[], true); + self.wait_for_completion(command_id, ()) } pub fn request<'r, R: Request>( &'r self, req: R, - ) -> Result, CommandError>>, Error> + ) -> Result< + impl Future, CommandError>>, + NvmeError, + > where R::Response: 'r, 'r: 'a, @@ -395,11 +396,11 @@ impl<'a> QueuePair<'a> { assert_ne!(size_of::(), 0); assert!(size_of::() < 0x1000); - let page = phys::alloc_page()?; + let page = phys::alloc_page().map_err(NvmeError::MemoryError)?; // TODO PageBox let response = unsafe { PhysicalRefMut::map(page) }; - let command_id = self.submit(req, &[page], true)?; + let command_id = self.submit(req, &[page], true); Ok(self.wait_for_completion(command_id, response)) } diff --git a/src/task/runtime/executor.rs b/src/task/runtime/executor.rs index 53f79473..5dab913c 100644 --- a/src/task/runtime/executor.rs +++ b/src/task/runtime/executor.rs @@ -7,7 +7,7 @@ use futures_util::{task::waker_ref, Future}; use crate::task::{spawn_kernel_closure, thread::Thread}; use super::{ - task::Task, + task::{Task, Termination}, task_queue::{self}, }; @@ -38,7 +38,9 @@ pub fn spawn_async_worker(index: usize) -> Result<(), Error> { } /// Creates a new task for the [Future] and queues it for execution in background -pub fn spawn + Send + 'static>(future: F) -> Result<(), Error> { +pub fn spawn + Send + 'static>( + future: F, +) -> Result<(), Error> { enqueue(Task::new(future)) } diff --git a/src/task/runtime/task.rs b/src/task/runtime/task.rs index 7a064c32..f28e034d 100644 --- a/src/task/runtime/task.rs +++ b/src/task/runtime/task.rs @@ -1,9 +1,15 @@ +use core::fmt; + use alloc::sync::Arc; use futures_util::{future::BoxFuture, task::ArcWake, Future, FutureExt}; use kernel_util::sync::IrqSafeSpinlock; use super::executor; +pub trait Termination { + fn print(&self); +} + pub struct Task { pub(super) future: IrqSafeSpinlock>>, } @@ -15,8 +21,25 @@ impl ArcWake for Task { } impl Task { - pub fn new + Send + 'static>(future: F) -> Arc { - let future = IrqSafeSpinlock::new(Some(future.boxed())); + pub fn new + Send + 'static>(future: F) -> Arc { + let future = IrqSafeSpinlock::new(Some( + async move { + future.await.print(); + } + .boxed(), + )); Arc::new(Self { future }) } } + +impl Termination for () { + fn print(&self) {} +} + +impl Termination for Result { + fn print(&self) { + if let Err(error) = self { + errorln!("A task finished with an error: {:?}", error); + } + } +}