Re: [PATCH v2 2/2] rust: virtio: add virtio support
From: Daniel Almeida
Date: Fri Apr 07 2023 - 19:36:55 EST
Hi Wedson, Martin,
First of all, thanks for the review.
> > + /// VirtIO driver remove.
> > + ///
> > + /// Called when a virtio device is removed.
> > + /// Implementers should prepare the device for complete
> > removal here.
> > + ///
> > + /// In particular, implementers must ensure no buffers are
> > left over in the
> > + /// virtqueues in use by calling [`virtqueue::get_buf()`]
> > until `None` is
> > + /// returned.
>
> What happens if implementers don't do this?
>
> If this is a safety requirement, we need to find a different way to
> enforce it.
>
> >
This is the worst part of this patch by far, unfortunately. If one
doesn't do this, then s/he will leak the `data` field passed in through
into_foreign() here:
> + // SAFETY: `self.ptr` is valid as per the type invariant.
> + let res = unsafe {
> + bindings::virtqueue_add_sgs(
> + self.ptr,
> + sgs.as_mut_ptr(),
> + num_out as u32,
> + num_in as u32,
> + data.into_foreign() as _,
> + gfp,
> + )
> + };
> +
Note the comment here:
> + // SAFETY: if there is a buffer token, it came from
> + // `into_foreign()` as called in `add_sgs()`.
> + <T::PrivateData as ForeignOwnable>::from_foreign(buf)
To be honest, I tried coming up with something clever to solve this,
but couldn't. Ideally this should happen when this function is called:
> + extern "C" fn remove_callback(virtio_device: *mut
bindings::virtio_device) {
But I did not find a way to iterate over the the `vqs` member from the
Rust side, i.e.:
```
struct virtio_device {
int index;
bool failed;
bool config_enabled;
bool config_change_pending;
spinlock_t config_lock;
spinlock_t vqs_list_lock; /* Protects VQs list access */
struct device dev;
struct virtio_device_id id;
const struct virtio_config_ops *config;
const struct vringh_config_ops *vringh_config;
struct list_head vqs; <------------------
```
Is there any wrappers over list_for_each_entry(), etc, to be used from
Rust? If so, I could not find them.
Doing this cleanup from Virtqueue::Drop() is not an option either:
since we wrap over a pointer owned by the kernel, there's no guarantee
that the actual virtqueue is going away when drop is called on the
wrapper. In fact, this is never the case, as virtqueues are deleted
through this call:
> +void rust_helper_virtio_del_vqs(struct virtio_device *vdev)
> +{
> + vdev->config->del_vqs(vdev);
> +}
> +
Suggestions welcome,
-- Daniel