kernel/device/block/
mod.rs

1use core::any::Any;
2
3use alloc::{boxed::Box, vec::Vec};
4use request::{BlockIORequest, BlockIOResult};
5use spin::Mutex;
6
7use super::Device;
8use crate::object::capability::selectable::Selectable;
9use crate::object::capability::{ControlOps, MemoryMappingOps};
10
11pub mod request;
12
13extern crate alloc;
14
15/// Block device interface
16///
17/// This trait defines the interface for block devices.
18/// It provides methods for querying device information and handling I/O requests.
19pub trait BlockDevice: Device {
20    /// Get the disk name
21    fn get_disk_name(&self) -> &'static str;
22
23    /// Get the disk size in bytes
24    fn get_disk_size(&self) -> usize;
25
26    /// Enqueue a block I/O request
27    fn enqueue_request(&self, request: Box<BlockIORequest>);
28
29    /// Process all queued requests
30    ///
31    /// # Returns
32    ///
33    /// A vector of results for all processed requests
34    fn process_requests(&self) -> Vec<BlockIOResult>;
35}
36
37/// A generic implementation of a block device
38pub struct GenericBlockDevice {
39    disk_name: &'static str,
40    disk_size: usize,
41    request_fn: fn(&mut BlockIORequest) -> Result<(), &'static str>,
42    request_queue: Mutex<Vec<Box<BlockIORequest>>>,
43}
44
45impl GenericBlockDevice {
46    pub fn new(
47        disk_name: &'static str,
48        disk_size: usize,
49        request_fn: fn(&mut BlockIORequest) -> Result<(), &'static str>,
50    ) -> Self {
51        Self {
52            disk_name,
53            disk_size,
54            request_fn,
55            request_queue: Mutex::new(Vec::new()),
56        }
57    }
58}
59
60impl Device for GenericBlockDevice {
61    fn device_type(&self) -> super::DeviceType {
62        super::DeviceType::Block
63    }
64
65    fn name(&self) -> &'static str {
66        self.disk_name
67    }
68
69    fn as_any(&self) -> &dyn Any {
70        self
71    }
72
73    fn as_any_mut(&mut self) -> &mut dyn Any {
74        self
75    }
76
77    fn as_block_device(&self) -> Option<&dyn BlockDevice> {
78        Some(self)
79    }
80}
81
82impl ControlOps for GenericBlockDevice {
83    // Generic block devices don't support control operations by default
84    fn control(&self, _command: u32, _arg: usize) -> Result<i32, &'static str> {
85        Err("Control operations not supported")
86    }
87}
88
89impl MemoryMappingOps for GenericBlockDevice {
90    fn get_mapping_info(
91        &self,
92        _offset: usize,
93        _length: usize,
94    ) -> Result<(usize, usize, bool), &'static str> {
95        Err("Memory mapping not supported by this block device")
96    }
97
98    fn on_mapped(&self, _vaddr: usize, _paddr: usize, _length: usize, _offset: usize) {
99        // Generic block devices don't support memory mapping
100    }
101
102    fn on_unmapped(&self, _vaddr: usize, _length: usize) {
103        // Generic block devices don't support memory mapping
104    }
105
106    fn supports_mmap(&self) -> bool {
107        false
108    }
109}
110
111impl Selectable for GenericBlockDevice {
112    fn wait_until_ready(
113        &self,
114        _interest: crate::object::capability::selectable::ReadyInterest,
115        _trapframe: &mut crate::arch::Trapframe,
116        _timeout_ticks: Option<u64>,
117    ) -> crate::object::capability::selectable::SelectWaitOutcome {
118        crate::object::capability::selectable::SelectWaitOutcome::Ready
119    }
120}
121
122impl BlockDevice for GenericBlockDevice {
123    fn get_disk_name(&self) -> &'static str {
124        self.disk_name
125    }
126
127    fn get_disk_size(&self) -> usize {
128        self.disk_size
129    }
130
131    fn enqueue_request(&self, request: Box<BlockIORequest>) {
132        // Use Mutex for internal mutability
133        self.request_queue.lock().push(request);
134    }
135
136    /// Process all queued block I/O requests
137    ///
138    /// This method processes all pending requests using a lock-efficient approach:
139    ///
140    /// 1. Acquires the request_queue lock once
141    /// 2. Extracts all requests at once using mem::replace
142    /// 3. Releases the lock immediately
143    /// 4. Processes all requests without holding any locks
144    ///
145    /// This approach minimizes lock contention and prevents deadlocks by:
146    /// - Never holding the lock during request processing
147    /// - Allowing other threads to enqueue requests while processing
148    /// - Avoiding any circular lock dependencies
149    ///
150    /// # Returns
151    /// Vector of `BlockIOResult` containing completed requests and their results
152    fn process_requests(&self) -> Vec<BlockIOResult> {
153        let mut results = Vec::new();
154
155        // Extract all requests at once to minimize lock time
156        let requests = {
157            let mut queue = self.request_queue.lock();
158            core::mem::replace(&mut *queue, Vec::new())
159        }; // Lock is automatically released here
160
161        // Process all requests without holding any locks
162        for mut request in requests {
163            // Process the request using the function pointer
164            let result = (self.request_fn)(&mut *request);
165
166            // Add the result to the results vector
167            results.push(BlockIOResult { request, result });
168        }
169
170        results
171    }
172}
173
174#[cfg(test)]
175mod tests;
176
177#[cfg(test)]
178pub mod mockblk;