virtio_drivers::device::blk

Struct VirtIOBlk

Source
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>

Source

pub fn new(transport: T) -> Result<Self>

Create a new VirtIO-Blk driver.

Source

pub fn capacity(&self) -> u64

Gets the capacity of the block device, in 512 byte (SECTOR_SIZE) sectors.

Source

pub fn readonly(&self) -> bool

Returns true if the block device is read-only, or false if it allows writes.

Source

pub fn ack_interrupt(&mut self) -> bool

Acknowledges a pending interrupt, if any.

Returns true if there was an interrupt to acknowledge.

Source

pub fn enable_interrupts(&mut self)

Enables interrupts from the device.

Source

pub fn disable_interrupts(&mut self)

Disables interrupts from the device.

Source

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.

Source

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.

Source

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.

Source

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 as read_blocks_nb will initialise it, but like the other buffers it needs to be valid (and not otherwise used) until the corresponding complete_read_blocks call. Its length must be a non-zero multiple of SECTOR_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.

Source

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.

Source

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.

Source

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 as read_blocks_nb will initialise it, but like the other buffers it needs to be valid (and not otherwise used) until the corresponding complete_write_blocks call.
  • buf - The buffer in memory containing the data to write to the blocks. Its length must be a non-zero multiple of SECTOR_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

See VirtIOBlk::read_blocks_nb.

Source

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.

Source

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.

Source

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.

Trait Implementations§

Source§

impl<H: Hal, T: Transport> Drop for VirtIOBlk<H, T>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

§

impl<H, T> Freeze for VirtIOBlk<H, T>
where T: Freeze,

§

impl<H, T> RefUnwindSafe for VirtIOBlk<H, T>
where T: RefUnwindSafe, H: RefUnwindSafe,

§

impl<H, T> Send for VirtIOBlk<H, T>
where T: Send,

§

impl<H, T> Sync for VirtIOBlk<H, T>
where T: Sync,

§

impl<H, T> Unpin for VirtIOBlk<H, T>
where T: Unpin, H: Unpin,

§

impl<H, T> UnwindSafe for VirtIOBlk<H, T>
where T: UnwindSafe, H: UnwindSafe,

Blanket Implementations§

§

impl<T> Any for T
where T: 'static + ?Sized,

§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> Borrow<T> for T
where T: ?Sized,

§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
§

impl<T> BorrowMut<T> for T
where T: ?Sized,

§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> From<T> for T

§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T, U> Into<U> for T
where U: From<T>,

§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of [From]<T> for U chooses to do.

§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.