Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New virtio blk driver #96

Open
wants to merge 15 commits into
base: master
Choose a base branch
from

Conversation

Arsering
Copy link
Contributor

No description provided.

Copy link
Contributor Author

@Arsering Arsering left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add several new features to virtio-blk driver, including:

  1. packed queue
  2. indirect descriptor for packed queue and split queue
  3. complete two device commands: VIRTIO_BLK_T_IN and VIRTIO_BLK_T_OUT (supporting read/write multiple blocks in one request)
  4. add six new commands: VIRTIO_BLK_T_DISCARD, VIRTIO_BLK_T_WRITE_ZEROES, VIRTIO_BLK_T_FLUSH, VIRTIO_BLK_T_GET_ID, VIRTIO_BLK_T_SECURE_ERASE, VIRTIO_BLK_T_GET_LIFETIME (polling and interrupt)
  5. support asynchronous I/O (future in Rust)

@qwandor qwandor self-requested a review June 19, 2023 16:51
Copy link
Collaborator

@qwandor qwandor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! There's a lot going on here, so it's going to take a while to review it all. For a start, I've reviewed the indirect descriptor support and a few related parts.

If you'd like to get this merged more quickly it might be better to split out the other changes (packed queue, more block device features) into separate PRs.

@@ -65,15 +65,18 @@ pub struct ConsoleInfo {
impl<H: Hal, T: Transport> VirtIOConsole<H, T> {
/// Creates a new VirtIO console driver.
pub fn new(mut transport: T) -> Result<Self> {
// TODO:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to do something or write something more here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My primary focus is on improving the virtio-blk driver, and the usage of "TODO" here is to notify someone that the indirect descriptor is not supported in the virtio-console driver. I will make the necessary modifications to clearly convey my intention.

src/lib.rs Outdated
pub mod transport;
mod virtio_queue;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why rename the module? Given that this is the virtio-drivers crate, it seems like it should be fairly clear that the queue module is for virt queues.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the rename is unnecessary and I will fix it

@@ -1,4 +1,4 @@
#![deny(unsafe_op_in_unsafe_fn)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep this deny please, it helps keep unsafe code a bit more contained.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

use core::sync::atomic::{fence, Ordering};
use log::info;
use zerocopy::FromBytes;
// use log::{debug, info};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this line, there's no point keeping it commented-out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I will fix it

/// The mechanism for bulk data transport on virtio devices.
///
/// Each device can have zero or more virtqueues.
///
/// * `SIZE`: The size of the queue. This is both the number of descriptors, and the number of slots
/// in the available and used rings.
/// * `SIZE`: The size of the queue. This is both the number of descriptors, and the number of slots in the available and used rings. Queue Size value is always a power of 2. The maximum Queue Size value is 32768. This value is specified in a bus-specific way.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: wrap comments to 100 columns, to match the rest of the file. (Both this and the rest of the comments lower down.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I will fix it

///
/// Ref: virtio_ring.c virtqueue_kick_prepare_split
/// This will be false if the device has supressed notifications.
pub fn should_notify_old(&self) -> bool {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise, please just change the callers to pass false rather than having two versions of the method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK

@@ -1,4 +1,4 @@
#![deny(unsafe_op_in_unsafe_fn)]
extern crate alloc;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't be necessary here, only in the top-level lib.rs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I will fix it

@@ -280,11 +409,57 @@ impl<H: Hal, const SIZE: usize> VirtQueue<H, SIZE> {
self.free_head = head;
let mut next = Some(head);

for (buffer, direction) in InputOutputIter::new(inputs, outputs) {
if self.indirect_desc {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You still need to loop through all the buffers and unshare them with H::unshare, to avoid leaking DMA memory on platforms that allocate it separately (and potentially missing the response entirely, as unshare may also copy the data back to the original buffer).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, let me fix it

// TODO: will be deleted in the further
/// The buffers in `inputs` and `outputs` must match the set of buffers originally added to the
/// queue by `add`.
unsafe fn recycle_descriptors_async<'a>(&mut self, head: u16) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also needs to call H::unshare on each buffer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I will fix it

@@ -553,6 +794,15 @@ impl Descriptor {
None
}
}

fn new() -> Self {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: you could just derive Default instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, nice suggestion

@qwandor
Copy link
Collaborator

qwandor commented Jul 11, 2023

I've split out some of the new block device driver features into #100 so we can get that in first. Please take a look. The support for packed queues and indirect descriptors is going to require more thought, as the approach taken in this PR doesn't handle DMA memory properly. The async IO parts of this PR have some soundness issues.

@qwandor
Copy link
Collaborator

qwandor commented Jul 13, 2023

@Arsering I've pulled out the indirect descriptor support from this PR into #102 and fixed the DMA allocation issues and a few other things, and written some tests. Please take a look at that and let me know what you think.

// Read barrier, so we read a fresh value from the device.
fence(Ordering::SeqCst);

// Safe because self.used points to a valid, aligned, initialised, dereferenceable, readable
// instance of UsedRing.
if support_event {
unsafe { (*self.avail.as_ptr()).idx == (*self.used.as_ptr()).avail_event }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use self.avail_idx rather than reading from the available ring directly, because we don't trust the device not to modify the available ring (even though it shouldn't).

Also, from my reading of the spec, it sounds like we should be checking for avail_idx == avail_event.wrapping_add(1), as should_notify is called after avail_idx is updated. See 2.7.10.2: "equivalently, until idx in the available ring will reach the value avail_event + 1".

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll send a separate PR to add event_idx support with this fixed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me read the spec again to figure it out

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants