kernel/device/block/
mod.rs

1use core::any::Any;
2
3use alloc::{boxed::Box, vec::Vec};
4use spin::Mutex;
5use request::{BlockIORequest, BlockIOResult};
6
7use super::Device;
8
9pub mod request;
10
11extern crate alloc;
12
13/// Block device interface
14/// 
15/// This trait defines the interface for block devices.
16/// It provides methods for querying device information and handling I/O requests.
17pub trait BlockDevice: Device {
18    /// Get the disk name
19    fn get_disk_name(&self) -> &'static str;
20    
21    /// Get the disk size in bytes
22    fn get_disk_size(&self) -> usize;
23    
24    /// Enqueue a block I/O request
25    fn enqueue_request(&self, request: Box<BlockIORequest>);
26    
27    /// Process all queued requests
28    /// 
29    /// # Returns
30    /// 
31    /// A vector of results for all processed requests
32    fn process_requests(&self) -> Vec<BlockIOResult>;
33}
34
35/// A generic implementation of a block device
36pub struct GenericBlockDevice {
37    disk_name: &'static str,
38    disk_size: usize,
39    request_fn: fn(&mut BlockIORequest) -> Result<(), &'static str>,
40    request_queue: Mutex<Vec<Box<BlockIORequest>>>,
41}
42
43impl GenericBlockDevice {
44    pub fn new(disk_name: &'static str, disk_size: usize, request_fn: fn(&mut BlockIORequest) -> Result<(), &'static str>) -> Self {
45        Self { disk_name, disk_size, request_fn, request_queue: Mutex::new(Vec::new()) }
46    }
47}
48
49impl Device for GenericBlockDevice {
50    fn device_type(&self) -> super::DeviceType {
51        super::DeviceType::Block
52    }
53
54    fn name(&self) -> &'static str {
55        self.disk_name
56    }
57
58    fn as_any(&self) -> &dyn Any {
59        self
60    }
61    
62    fn as_any_mut(&mut self) -> &mut dyn Any {
63        self
64    }
65    
66    fn as_block_device(&self) -> Option<&dyn BlockDevice> {
67        Some(self)
68    }
69}
70
71impl BlockDevice for GenericBlockDevice {
72    fn get_disk_name(&self) -> &'static str {
73        self.disk_name
74    }
75
76    fn get_disk_size(&self) -> usize {
77        self.disk_size
78    }
79
80    fn enqueue_request(&self, request: Box<BlockIORequest>) {
81        // Use Mutex for internal mutability
82        self.request_queue.lock().push(request);
83    }
84
85    /// Process all queued block I/O requests
86    /// 
87    /// This method processes all pending requests using a lock-efficient approach:
88    /// 
89    /// 1. Acquires the request_queue lock once
90    /// 2. Extracts all requests at once using mem::replace
91    /// 3. Releases the lock immediately
92    /// 4. Processes all requests without holding any locks
93    /// 
94    /// This approach minimizes lock contention and prevents deadlocks by:
95    /// - Never holding the lock during request processing
96    /// - Allowing other threads to enqueue requests while processing
97    /// - Avoiding any circular lock dependencies
98    /// 
99    /// # Returns
100    /// Vector of `BlockIOResult` containing completed requests and their results
101    fn process_requests(&self) -> Vec<BlockIOResult> {
102        let mut results = Vec::new();
103        
104        // Extract all requests at once to minimize lock time
105        let requests = {
106            let mut queue = self.request_queue.lock();
107            core::mem::replace(&mut *queue, Vec::new())
108        }; // Lock is automatically released here
109        
110        // Process all requests without holding any locks
111        for mut request in requests {
112            // Process the request using the function pointer
113            let result = (self.request_fn)(&mut *request);
114            
115            // Add the result to the results vector
116            results.push(BlockIOResult { request, result });
117        }
118        
119        results
120    }
121}
122
123#[cfg(test)]
124mod tests;
125
126#[cfg(test)]
127pub mod mockblk;