|
@@ -88,42 +88,63 @@ impl<H: Hal, T: Transport> VirtIOBlk<H, T> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /// Read a block in a non-blocking way which means that it returns immediately.
|
|
|
+ /// Submits a request to read a block, but returns immediately without waiting for the read to
|
|
|
+ /// complete.
|
|
|
///
|
|
|
/// # Arguments
|
|
|
///
|
|
|
/// * `block_id` - The identifier of the block to read.
|
|
|
- /// * `buf` - The buffer in the memory which the block is read into.
|
|
|
+ /// * `req` - A buffer which the driver can use for the request to send to the device. The
|
|
|
+ /// contents don't matter as `read_block_nb` will initialise it, but like the other buffers it
|
|
|
+ /// needs to be valid (and not otherwise used) until the corresponding `pop_used` call.
|
|
|
+ /// * `buf` - The buffer in memory into which the block should be read.
|
|
|
/// * `resp` - A mutable reference to a variable provided by the caller
|
|
|
- /// which contains the status of the requests. The caller can safely
|
|
|
- /// read the variable only after the request is ready.
|
|
|
+ /// to contain the status of the request. The caller can safely
|
|
|
+ /// read the variable only after the request is complete.
|
|
|
///
|
|
|
/// # Usage
|
|
|
///
|
|
|
- /// It will submit request to the virtio block device and return a token identifying
|
|
|
+ /// It will submit request to the VirtIO block device and return a token identifying
|
|
|
/// the position of the first Descriptor in the chain. If there are not enough
|
|
|
/// Descriptors to allocate, then it returns [Error::BufferTooSmall].
|
|
|
///
|
|
|
- /// After the request is ready, `resp` will be updated and the caller can get the
|
|
|
- /// status of the request(e.g. succeed or failed) through it. However, the caller
|
|
|
- /// **must not** spin on `resp` to wait for it to change. A safe way is to read it
|
|
|
- /// after the same token as this method returns is fetched through [VirtIOBlk::pop_used()],
|
|
|
- /// which means that the request has been ready.
|
|
|
+ /// The caller can then call `pop_used` to check whether the device has finished handling the
|
|
|
+ /// request. Once it has, the caller can then read the response and dispose of the buffers.
|
|
|
+ ///
|
|
|
+ /// ```
|
|
|
+ /// # use virtio_drivers::{BlkReq, BlkResp, Error, Hal, RespStatus, Transport, VirtIOBlk};
|
|
|
+ /// # fn example<H: Hal, T: Transport>(blk: &mut VirtIOBlk<H, T>) -> Result<(), Error> {
|
|
|
+ /// let mut request = BlkReq::default();
|
|
|
+ /// let mut buffer = [0; 512];
|
|
|
+ /// let mut response = BlkResp::default();
|
|
|
+ /// let token = unsafe { blk.read_block_nb(42, &mut request, &mut buffer, &mut response) }?;
|
|
|
+ ///
|
|
|
+ /// // Wait for an interrupt to tell us that the request completed...
|
|
|
+ ///
|
|
|
+ /// assert_eq!(blk.pop_used()?, token);
|
|
|
+ /// if response.status() == RespStatus::OK {
|
|
|
+ /// println!("Successfully read block.");
|
|
|
+ /// } else {
|
|
|
+ /// println!("Error {:?} reading block.", response.status());
|
|
|
+ /// }
|
|
|
+ /// # Ok(())
|
|
|
+ /// # }
|
|
|
+ /// ```
|
|
|
///
|
|
|
/// # Safety
|
|
|
///
|
|
|
- /// `buf` is still borrowed by the underlying virtio block device even if this
|
|
|
- /// method returns. Thus, it is the caller's responsibility to guarantee that
|
|
|
- /// `buf` is not accessed before the request is completed in order to avoid
|
|
|
- /// data races.
|
|
|
+ /// `req`, `buf` and `resp` are still borrowed by the underlying VirtIO block device even after
|
|
|
+ /// this method returns. Thus, it is the caller's responsibility to guarantee that they are not
|
|
|
+ /// accessed before the request is completed in order to avoid data races.
|
|
|
pub unsafe fn read_block_nb(
|
|
|
&mut self,
|
|
|
block_id: usize,
|
|
|
+ req: &mut BlkReq,
|
|
|
buf: &mut [u8],
|
|
|
resp: &mut BlkResp,
|
|
|
) -> Result<u16> {
|
|
|
assert_eq!(buf.len(), SECTOR_SIZE);
|
|
|
- let req = BlkReq {
|
|
|
+ *req = BlkReq {
|
|
|
type_: ReqType::In,
|
|
|
reserved: 0,
|
|
|
sector: block_id as u64,
|
|
@@ -155,31 +176,36 @@ impl<H: Hal, T: Transport> VirtIOBlk<H, T> {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- //// Write a block in a non-blocking way which means that it returns immediately.
|
|
|
+ /// Submits a request to write a block, but returns immediately without waiting for the write to
|
|
|
+ /// complete.
|
|
|
///
|
|
|
/// # Arguments
|
|
|
///
|
|
|
/// * `block_id` - The identifier of the block to write.
|
|
|
- /// * `buf` - The buffer in the memory containing the data to write to the block.
|
|
|
+ /// * `req` - A buffer which the driver can use for the request to send to the device. The
|
|
|
+ /// contents don't matter as `read_block_nb` will initialise it, but like the other buffers it
|
|
|
+ /// needs to be valid (and not otherwise used) until the corresponding `pop_used` call.
|
|
|
+ /// * `buf` - The buffer in memory containing the data to write to the block.
|
|
|
/// * `resp` - A mutable reference to a variable provided by the caller
|
|
|
- /// which contains the status of the requests. The caller can safely
|
|
|
- /// read the variable only after the request is ready.
|
|
|
+ /// to contain the status of the request. The caller can safely
|
|
|
+ /// read the variable only after the request is complete.
|
|
|
///
|
|
|
/// # Usage
|
|
|
///
|
|
|
- /// See also [VirtIOBlk::read_block_nb()].
|
|
|
+ /// See [VirtIOBlk::read_block_nb].
|
|
|
///
|
|
|
/// # Safety
|
|
|
///
|
|
|
- /// See also [VirtIOBlk::read_block_nb()].
|
|
|
+ /// See [VirtIOBlk::read_block_nb].
|
|
|
pub unsafe fn write_block_nb(
|
|
|
&mut self,
|
|
|
block_id: usize,
|
|
|
+ req: &mut BlkReq,
|
|
|
buf: &[u8],
|
|
|
resp: &mut BlkResp,
|
|
|
) -> Result<u16> {
|
|
|
assert_eq!(buf.len(), SECTOR_SIZE);
|
|
|
- let req = BlkReq {
|
|
|
+ *req = BlkReq {
|
|
|
type_: ReqType::Out,
|
|
|
reserved: 0,
|
|
|
sector: block_id as u64,
|
|
@@ -231,14 +257,25 @@ struct BlkConfig {
|
|
|
// ... ignored
|
|
|
}
|
|
|
|
|
|
+/// A VirtIO block device request.
|
|
|
#[repr(C)]
|
|
|
#[derive(AsBytes, Debug)]
|
|
|
-struct BlkReq {
|
|
|
+pub struct BlkReq {
|
|
|
type_: ReqType,
|
|
|
reserved: u32,
|
|
|
sector: u64,
|
|
|
}
|
|
|
|
|
|
+impl Default for BlkReq {
|
|
|
+ fn default() -> Self {
|
|
|
+ Self {
|
|
|
+ type_: ReqType::In,
|
|
|
+ reserved: 0,
|
|
|
+ sector: 0,
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/// Response of a VirtIOBlk request.
|
|
|
#[repr(C)]
|
|
|
#[derive(AsBytes, Debug, FromBytes)]
|