-
Notifications
You must be signed in to change notification settings - Fork 89
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
virtio_queue: Add descriptors_utils.rs #278
virtio_queue: Add descriptors_utils.rs #278
Conversation
@germag feel free to comment. |
@MatiasVara thanks a lot for updating this! This is something which we really need. I will review this tomorrow in more detail! Just a couple of minor comments before diving into a review:
|
I missed those two points from our previous discussion. I will add a reference to the virtiofsd version. In regards to the second point, I just did a quick review of the crosvm version and found that it doesn't require a lifetime parameter when instantiated. However, I did not go any further. The differences may need to be better understood. |
Is virtiofsd's read/write_at not likely to be useful for other backends? Is it a very special case only virtiofsd benefits from? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some random comments, but nothing extraordinary. One thing I wonder about is whether the separation into Reader and Writer makes a lot of sense for the user.
Does a user of this really care that much about it? I wonder whether it could not be a single object and the API could be used something like:
for desc_chain in requests {
let header = desc_chain.read_obj::<SomeHeader>()?;
let response = ...;
desc_chain.write_obj(response)?;
}
(maybe overly simplified, but should show the idea)
With the proposed API here that has to be done manually like writter_status.split_at(size_of::<VirtioSoundHeader>())
. While this certainly bring great improvements for the user, I wonder whether the ergonomics could be even better with a single object? 🤔 Sure, some special case may require "seeking" in the chain, but I guess 90%+ of the uses will just be sequential processing/parsing followed by writing the answer?
// writes are happening. | ||
unsafe { | ||
copy_nonoverlapping(rem.as_ptr(), vs.ptr_guard_mut().as_ptr(), copy_len); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
slice.read_volatile(vs)
here :)
Probably, I can add them if they are required for other backends. If not, I believe each device can "adapt or extend" current traits to suit its particular needs. |
@Ablu Thanks for the review! I will try to answer some of the comments during today.
Having a single object would simplify things. My guess about this design is that the chain of descriptors could be divided into two areas: a chain with read-only descriptors followed by a chain with write-only descriptors. This is the only requirement from the virtio-spec about the descriptors distribution (2.6.4.2 in Virtio Spec v1.1). As far as I understand it, when a Reader and Writer are instantiated, they "point" to the beginning of the area they correspond to. A single object shall automatically take into account such an offset. This is not a problem at all, and such a logic should be added to |
Ah. Did not realize that readable first, writeable after that even was a global rule. Not sure whether we need specific logic to verify this (they flags on the descriptor sound sufficient to me). But it confirms that read, then write is the only case :). @MatiasVara: Want to try to adapt it to a single object? Eventually, I think we should target for this API being the default way to work with descriptors. So probably the descriptor chain iterator on the queue should in the end just return something that implements this high-level API :). |
Yes, I can try to adapt it to a single object. |
Would it make sense an interface like this? Note that this is just a draft and names will be different: pub struct Walker<'a>{
r: Reader<'a>,
w: Writer<'a>,
payload: Writer<'a>
}
impl <'a> Walker<'a>{
pub fn new<M>(
mem: &'a GuestMemoryMmap,
desc_chain: DescriptorChain<M>,
offset: usize
) -> Result<Walker<'a>>
where
M: Deref,
M: Clone,
M::Target: GuestMemory + Sized,
{
let reader = Reader::new(mem, desc_chain.clone()).unwrap();
let mut writer = Writer::new(mem, desc_chain.clone()).unwrap();
let payload = writer.split_at(offset).unwrap();
Ok(Walker {
r: reader,
w: writer,
payload
})
}
pub fn read_obj<T: ByteValued>(&mut self) -> io::Result<T> {
self.r.read_obj()
}
pub fn write_obj<T: ByteValued>(&mut self, val: T) -> io::Result<()> {
self.w.write_obj(val)
}
pub fn write_payload_obj<T: ByteValued>(&mut self, val: T) -> io::Result<()> {
self.payload.write_obj(val)
}
} I do not think payload is required for all the devices. In those cases, I would set |
What is the |
I used to use the |
I wonder: Why do we need separate Reader/Writer types at all? Couldn't we just use one that implements read/write mechanism directly (a bit like Cursor from the standard lib)? |
Could you elaborate?, Thanks. |
mmm, |
Sorry for not being super clear... What I meant was I see no pressing need for having Going back to what I sketched before:
Here, descriptor_chain could directly be what this PR currently calls I am not exactly sure whether I understand why the payload differentiation is needed though. Why can't I just do:
🤔 |
Could you elaborate? I proposed payload to work around |
Yeah, but this is meaningful only for virtio-sound, because for example for virito-blk the For some others maybe
If we want a single Walker, then maybe we need to provide methods to split the Walker, but I don't think we should split into header and payload in it, because that's really device-specific and the user has to do the split. |
I think you can't use the same
I used payload to work around |
I wonder: Couldn't one just |
I think the example could be rewritten as the following draft: desc_chain_reader.read_obj::<SomeHeader>()?;
desc_chain_writer.write_obj(payload)?;
desc_chain_writer_status = desc_chain_writer.clone();
desc_chain_writer_status.seek(sizeof(payload)); // note that seek() is not currently implemented
desc_chain_writer.write_obj(status)?; I think it is still required to separate the reader.read_obj::<SomeHeader>()?;
writer_status = writer_content.split_at(sizeof(payload))
writer_status.write_obj(status)?; This allows users to easily share I think we have to modify current implementation only if changes improve the way it is currently used. It is also true that those changes may raise after some utilization in the future. The other way to think would be to let each device add |
Why is that? 🤔 Chances are that I misunderstand something, but I have not found the reason spelled out so far.
I think unless we have some upstream solution, people probably won't put the brain cycles into creating a one-fits-all solutions that suits everyone equally well. I was hoping that one could turn it into a simpler to use API with just a few tweaks. I will try to play with this somewhen during this week and see how it feels. |
I did not explain myself very well, I meant that Reader relies on |
Thanks, I spotted some functions and corner cases that were not covered. Some of them are:
I will add tests for them. |
8467762
to
efc1885
Compare
Except for the license (which as I've already written I think is a pre-existing problem to be discussed separately), the rest seems to me to be in very good shape and I will try to use it in @MatiasVara thanks for this effort! |
f142662
to
b4525f1
Compare
b4525f1
to
5066fe0
Compare
Thanks again for working on this! This will greatly simplify descriptor walking and fix a lot of bugs in current code :) |
I was trying to use @Ablu @MatiasVara What do you think? |
Ah, I tried the same before but missed being able to set the lifetime via So it looks good to me. Yet, this interface in vm-memory is just way too complex to use without loosing sanity. I also dislike the Deref use in DescriptorChain. It disallows properly using lifetimes through it. IMHO it should just be a |
Yeah, I was inspired by virtio-vsock API: vm-virtio/virtio-vsock/src/packet.rs Line 418 in d219302
BTW, in the end I think I'll change the virtio-vsock API to accept Reader and Writer from the caller, so I'm not sure if I really need the changes I proposed. But if you think they can improve a bit this PR, feel free to incorporate.
Okay, so I'm not the only one who almost went crazy with it.... |
5066fe0
to
740cb20
Compare
I think is it is a good idea. I just pushed a version with the changes. |
740cb20
to
75c9101
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
This commit adds descriptors_utils.rs from virtiofsd. This module provides the Reader/Writer classes to iterate over descriptors. Devices shall rely on this interface instead of manipulate descriptors. The version in this commit removes read_to_at() and write_from_at() that are required only for virtiofsd. To instantiate these helpers, user shall use the reader()/writer() functions defined in the context of DescriptorChain. Co-developed-by: Stefano Garzarella <sgarzare@redhat.com> Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> Signed-off-by: Matias Ezequiel Vara Larsen <mvaralar@redhat.com>
75c9101
to
0068e9f
Compare
I'm going to merge this, since we want to use it in vhost-devices. |
Summary of the PR
This commit adds
descriptors_utils.rs
from virtiofsd (daa4e32). This module provides the Reader/Writer traits to iterate over descriptors. Devices shall rely on this interface instead of manipulate descriptors. The reason to this is that the distribution is driver-dependent, i.e., virtio does not force any particular way to distribute the data over descriptors. The version in this commit removesread_to_at()
andwrite_from_at()
functions that are required only for virtiofsd. This commit is on top of 0.9 tag. To try this module, I am adding support for it in the virtio-sound device at https://github.com/MatiasVara/vhost-device/tree/use-descriptor-utils-virtio-sound.Requirements
Before submitting your PR, please make sure you addressed the following
requirements:
git commit -s
), and the commitmessage has max 60 characters for the summary and max 75 characters for each
description line.
test.
Release" section of CHANGELOG.md (if no such section exists, please create one).
unsafe
code is properly documented.