pub struct VirtIOBlk<H: Hal, T: Transport> { /* private fields */ }
Expand description
Driver for a VirtIO block device.
This is a simple virtual block device, e.g. disk.
Read and write requests (and other exotic requests) are placed in the queue and serviced (probably out of order) by the device except where noted.
§Example
use virtio_drivers::device::blk::{VirtIOBlk, SECTOR_SIZE};
let mut disk = VirtIOBlk::<HalImpl, _>::new(transport)?;
println!("VirtIO block device: {} kB", disk.capacity() * SECTOR_SIZE as u64 / 2);
// Read sector 0 and then copy it to sector 1.
let mut buf = [0; SECTOR_SIZE];
disk.read_blocks(0, &mut buf)?;
disk.write_blocks(1, &buf)?;
Implementations§
Source§impl<H: Hal, T: Transport> VirtIOBlk<H, T>
impl<H: Hal, T: Transport> VirtIOBlk<H, T>
Sourcepub fn capacity(&self) -> u64
pub fn capacity(&self) -> u64
Gets the capacity of the block device, in 512 byte (SECTOR_SIZE
) sectors.
Sourcepub fn readonly(&self) -> bool
pub fn readonly(&self) -> bool
Returns true if the block device is read-only, or false if it allows writes.
Sourcepub fn ack_interrupt(&mut self) -> bool
pub fn ack_interrupt(&mut self) -> bool
Acknowledges a pending interrupt, if any.
Returns true if there was an interrupt to acknowledge.
Sourcepub fn enable_interrupts(&mut self)
pub fn enable_interrupts(&mut self)
Enables interrupts from the device.
Sourcepub fn disable_interrupts(&mut self)
pub fn disable_interrupts(&mut self)
Disables interrupts from the device.
Sourcepub fn flush(&mut self) -> Result
pub fn flush(&mut self) -> Result
Requests the device to flush any pending writes to storage.
This will be ignored if the device doesn’t support the VIRTIO_BLK_F_FLUSH
feature.
Sourcepub fn device_id(&mut self, id: &mut [u8; 20]) -> Result<usize>
pub fn device_id(&mut self, id: &mut [u8; 20]) -> Result<usize>
Gets the device ID.
The ID is written as ASCII into the given buffer, which must be 20 bytes long, and the used length returned.
Sourcepub fn read_blocks(&mut self, block_id: usize, buf: &mut [u8]) -> Result
pub fn read_blocks(&mut self, block_id: usize, buf: &mut [u8]) -> Result
Reads one or more blocks into the given buffer.
The buffer length must be a non-zero multiple of SECTOR_SIZE
.
Blocks until the read completes or there is an error.
Sourcepub unsafe fn read_blocks_nb(
&mut self,
block_id: usize,
req: &mut BlkReq,
buf: &mut [u8],
resp: &mut BlkResp,
) -> Result<u16>
pub unsafe fn read_blocks_nb( &mut self, block_id: usize, req: &mut BlkReq, buf: &mut [u8], resp: &mut BlkResp, ) -> Result<u16>
Submits a request to read one or more blocks, but returns immediately without waiting for the read to complete.
§Arguments
block_id
- The identifier of the first block to read.req
- A buffer which the driver can use for the request to send to the device. The contents don’t matter asread_blocks_nb
will initialise it, but like the other buffers it needs to be valid (and not otherwise used) until the correspondingcomplete_read_blocks
call. Its length must be a non-zero multiple ofSECTOR_SIZE
.buf
- The buffer in memory into which the block should be read.resp
- A mutable reference to a variable provided by the caller 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
the position of the first Descriptor in the chain. If there are not enough
Descriptors to allocate, then it returns Error::QueueFull
.
The caller can then call peek_used
with the returned token to check whether the device has
finished handling the request. Once it has, the caller must call complete_read_blocks
with
the same buffers before reading the response.
use virtio_drivers::device::blk::{BlkReq, BlkResp, RespStatus};
let mut request = BlkReq::default();
let mut buffer = [0; 512];
let mut response = BlkResp::default();
let token = unsafe { blk.read_blocks_nb(42, &mut request, &mut buffer, &mut response) }?;
// Wait for an interrupt to tell us that the request completed...
assert_eq!(blk.peek_used(), Some(token));
unsafe {
blk.complete_read_blocks(token, &request, &mut buffer, &mut response)?;
}
if response.status() == RespStatus::OK {
println!("Successfully read block.");
} else {
println!("Error {:?} reading block.", response.status());
}
§Safety
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.
Sourcepub unsafe fn complete_read_blocks(
&mut self,
token: u16,
req: &BlkReq,
buf: &mut [u8],
resp: &mut BlkResp,
) -> Result<()>
pub unsafe fn complete_read_blocks( &mut self, token: u16, req: &BlkReq, buf: &mut [u8], resp: &mut BlkResp, ) -> Result<()>
Completes a read operation which was started by read_blocks_nb
.
§Safety
The same buffers must be passed in again as were passed to read_blocks_nb
when it returned
the token.
Sourcepub fn write_blocks(&mut self, block_id: usize, buf: &[u8]) -> Result
pub fn write_blocks(&mut self, block_id: usize, buf: &[u8]) -> Result
Writes the contents of the given buffer to a block or blocks.
The buffer length must be a non-zero multiple of SECTOR_SIZE
.
Blocks until the write is complete or there is an error.
Sourcepub unsafe fn write_blocks_nb(
&mut self,
block_id: usize,
req: &mut BlkReq,
buf: &[u8],
resp: &mut BlkResp,
) -> Result<u16>
pub unsafe fn write_blocks_nb( &mut self, block_id: usize, req: &mut BlkReq, buf: &[u8], resp: &mut BlkResp, ) -> Result<u16>
Submits a request to write one or more blocks, but returns immediately without waiting for the write to complete.
§Arguments
block_id
- The identifier of the first block to write.req
- A buffer which the driver can use for the request to send to the device. The contents don’t matter asread_blocks_nb
will initialise it, but like the other buffers it needs to be valid (and not otherwise used) until the correspondingcomplete_write_blocks
call.buf
- The buffer in memory containing the data to write to the blocks. Its length must be a non-zero multiple ofSECTOR_SIZE
.resp
- A mutable reference to a variable provided by the caller to contain the status of the request. The caller can safely read the variable only after the request is complete.
§Usage
See VirtIOBlk::read_blocks_nb.
§Safety
Sourcepub unsafe fn complete_write_blocks(
&mut self,
token: u16,
req: &BlkReq,
buf: &[u8],
resp: &mut BlkResp,
) -> Result<()>
pub unsafe fn complete_write_blocks( &mut self, token: u16, req: &BlkReq, buf: &[u8], resp: &mut BlkResp, ) -> Result<()>
Completes a write operation which was started by write_blocks_nb
.
§Safety
The same buffers must be passed in again as were passed to write_blocks_nb
when it
returned the token.
Sourcepub fn peek_used(&mut self) -> Option<u16>
pub fn peek_used(&mut self) -> Option<u16>
Fetches the token of the next completed request from the used ring and returns it, without
removing it from the used ring. If there are no pending completed requests returns None
.
Sourcepub fn virt_queue_size(&self) -> u16
pub fn virt_queue_size(&self) -> u16
Returns the size of the device’s VirtQueue.
This can be used to tell the caller how many channels to monitor on.