-
Notifications
You must be signed in to change notification settings - Fork 102
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
[RFC] ReadVolatile
and WriteVolatile
traits for efficient data transfer from/to guest memory
#247
Conversation
0f8e22c
to
13bf04b
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.
We definitely need some kind of abstraction like this! I am just worrying a bit about the right level to introduce it... This implements the traits on VolatileSlice
. I wonder whether it would not be more useful to implement this on a higher level? We only have such crazy number of read/write calls because we lack read/write abstraction on a descriptor chain. Also, if we would implement these traits on a descriptor chain level of abstraction, vectored read and writes could be implemented fairly straight forward.
So: Do we need to have this on this abstraction layer? Or do we only have it here because we lack a higher-level abstraction layer? My feeling is that we will need an abstraction on descriptor-chain level. Mostly for preventing people to use these low-level APIs incorrectly, but it may also allow to solve two problems at once: Zero-overhead access and a lot simpler and less error-prone API. rust-vmm/vm-virtio#33 proposed such an API and may be a natural abstraction level to add these "0-copy" variant traits.
Do we have a use-case that we cannot solve with such a higher-level API?
APIs for transfering data/from guest memory are currently used outside of virtio stacks. For example, linux-loader uses these to copy the kernel to guest memory [1], and firecracker uses them to save guest memory to disk for snapshot purposes [2]. Neither of these could be solved if these traits only lived in vm-virtio. So in that sense, I think it makes sense to have some Read/Write abstractions at the vm-memory level. Having them at In a sense, this PR does not add anything new - it simply provides replacements for the APIs that got broken by #217, and deprecates the broken ones. As for vectored reads and writes, I definitely agree that they are a lot more naturally expressible at the virtio descriptor chain level (we actually have an implementation similar to what you describe in firecracker [3]). I actually was not able to come up with a nice solution here for how to offer them at the vm-memory level without restricting what the virtio level is able to do (for example, if we only offer As for why we have all the read/write, I think its mainly convenience. People did not want to convert everything to VolatileSlice before being able to call .read/.write, so everything that could be converted to VolatileSlice instead gained a .read/.write method that does the conversion and then delegates. Over time it just got kinda out of control because the semantics/naming between the various functions got out of sync. |
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.
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.
nothing else jumped to my eye :)
6a7aef4
to
2041e6c
Compare
How about also implementing |
Ahh, yes, I forgot about that! Originally I wanted to implement these traits for all |
0c210fd
to
111a160
Compare
Done, please have another look :) |
2ad8370
to
53ccffa
Compare
With rust-vmm#217, various `read_from` and `write_to` methods across vm-memory incurred a performance penalty due to an unneccesary copy of all data read and written. This is due to these functions operating on arbitrary Read/Write implementations, which cannot generally be assumed to respect the volatile semantics of guest memory. Additionally, they required taking slices to guest memory, which was undefined behavior. This patch series fixes those short-comings by introducing a pair of new traits, `ReadVolatile` and `WriteVolatile` which are identical to the standard library's `Read` and `Write` traits, with the difference being that they operate on `VolatileSlice`s instead of `&mut [u8]`. Using these traits will therefore not incur the performance penalty of rust-vmm#217. Additionally, this will make using the vm-memory library easier for users familiar with std::io, as the APIs will be more familiar (in particular, the unintuitive "swapping" of reader/writer src and dst of the old read_from/write_to APIs is resolved). Please note that `impl<T: AsRawFd> ReadVolatile for T` is not be possible, as the orphan rules will note that "upstream crates may add a new impl of trait std::os::fd::AsRawFd for type &[u8] in future versions". Signed-off-by: Patrick Roy <[email protected]>
Signed-off-by: Patrick Roy <[email protected]>
These are the equivalent of the old read_from and write_to functions from Bytes. They have the same semantics in the sense that they correctly handle reads/writes spanning multiple guest memory regions. Note that no equivalent will be introduced in Bytes itself, as that those usecases are completely met by turning whatever Bytes-impl one has to a VolatileSlice, and then using the traits directly. This also has the advantage of streamlining the bounds checking to the functions that return VolatileSlices. Furthermore updates the tests to no longer use the deprecated functions. Note that some negative tests are removed due to bounds checking happening in get_slice instead of read_from/write_to now. Signed-off-by: Patrick Roy <[email protected]>
Signed-off-by: Patrick Roy <[email protected]>
Also fix a formatting error that snuck in with 0.12.1. Signed-off-by: Patrick Roy <[email protected]>
@jiangliu @JonathanWoollett-Light sorry, I had to manually rebase on top of the last changes, could you have one last look please? |
@roypat: The Rust |
Mhh, for As for adapters for Tbh, I probably was a bit overzealous with deprecating the old functions here, if you want I'll be happy to just revert that part of this PR and make a patch release. |
Right... it probably does not make a lot of sense to support these...
Do you maybe want to draft a PR for that? Currently this is blocking the updates to latest vm-memory for a lot of crates.
Well, eventually we want to deprecate them anyway I guess? So we might as well just do it now and fix the code that depends on the old API. |
I think it might make sense, to avoid people having to do
Please have a look at #256 :)
Sure! |
See: rust-vmm/vm-memory#247 Signed-off-by: Bo Chen <[email protected]>
See: rust-vmm/vm-memory#247 Signed-off-by: Bo Chen <[email protected]>
See: rust-vmm/vm-memory#247 Signed-off-by: Bo Chen <[email protected]>
See: rust-vmm/vm-memory#247 Signed-off-by: Bo Chen <[email protected]>
See: rust-vmm/vm-memory#247 Signed-off-by: Bo Chen <[email protected]>
See: rust-vmm/vm-memory#247 Signed-off-by: Bo Chen <[email protected]>
See: rust-vmm/vm-memory#247 Signed-off-by: Bo Chen <[email protected]>
See: rust-vmm/vm-memory#247 Signed-off-by: Bo Chen <[email protected]>
See: rust-vmm/vm-memory#247 Signed-off-by: Bo Chen <[email protected]>
See: rust-vmm/vm-memory#247 Signed-off-by: Bo Chen <[email protected]>
Summary of the PR
With #217, various
read_from
andwrite_to
methods across vm-memoryincurred a performance penalty due to an additional copy of all data
read and written. This is due to these functions operating on arbitrary
Read/Write implementations, which cannot generally be assumed to respect
the volatile semantics of guest memory. Additionally, they required
taking slices to guest memory, which was undefined behavior.
This patch series fixes those short-comings by introducing a pair of new
traits,
ReadVolatile
andWriteVolatile
which are identical to thestandard library's
Read
andWrite
traits, with the difference beingthat they operate on
VolatileSlice
s instead of&mut [u8]
. Usingthese traits will therefore not incur the performance penalty of #217.
Additionally, this will make using the vm-memory library easier for
users familiar with std::io, as the APIs will be more familiar (in
particular, the unintuitive "swapping" of reader/writer src and dst of
the old
read_from
/write_to
APIs is resolved).Please consider this as a not-completely-polished proposal for which I am seeking feedback. The code is based on what we wrote in firecracker to mitigate the performance impact of upgrading to 0.10.0 as a result of #217.
Open Questions
readv
/writev
. I think there is definitely a usecase for this, since both firecracker and virtio-fsd use vectored I/O in various places. It would be nice to upstream something similar to https://gitlab.com/virtio-fs/virtiofsd/-/blob/main/src/file_traits.rs toReadVolatile
/WriteVolatile
. Maybe someone from that team could chime in?read
andwrite
functions in this crate, but considered that change to be somewhat out of scope here (with this PR only aiming to address the inability to transfer data efficiently between a file descriptor and guest memory). I feel however that deprecating allread
/write
functions would greatly simplify this library at the cost of users having to callget_slice()
. Maybe via turning theBytes
trait into something that represents "self
can be turned into aVolatileSlice
", asread
->read_volatile
,read_slice
->read_exact_volatile
,write
->write_volatile
andwrite_slice
->write_all_volatile
.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.