Skip to content

Commit 31bdddb

Browse files
committed
implement userspace bounce buffering support
Add support to our virtio devices to allow userspace bounce buffering of virtio buffers. This is an alternative to swiotlb. Don't implement it for vhost-user-blk and for virtio-block with async engine, because I have no idea how that would even work. Signed-off-by: Patrick Roy <roypat@amazon.co.uk>
1 parent c809992 commit 31bdddb

File tree

21 files changed

+259
-35
lines changed

21 files changed

+259
-35
lines changed

src/vmm/src/device_manager/mmio.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,14 @@ mod tests {
600600

601601
fn set_acked_features(&mut self, _: u64) {}
602602

603+
fn force_userspace_bounce_buffers(&mut self) {
604+
todo!()
605+
}
606+
607+
fn userspace_bounce_buffers(&self) -> bool {
608+
todo!()
609+
}
610+
603611
fn device_type(&self) -> u32 {
604612
0
605613
}

src/vmm/src/devices/virtio/balloon/device.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,14 @@ impl VirtioDevice for Balloon {
557557
self.acked_features = acked_features;
558558
}
559559

560+
fn force_userspace_bounce_buffers(&mut self) {
561+
// balloon device doesn't have a need for bounce buffers
562+
}
563+
564+
fn userspace_bounce_buffers(&self) -> bool {
565+
false
566+
}
567+
560568
fn device_type(&self) -> u32 {
561569
TYPE_BALLOON
562570
}

src/vmm/src/devices/virtio/block/device.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,20 @@ impl VirtioDevice for Block {
148148
}
149149
}
150150

151+
fn force_userspace_bounce_buffers(&mut self) {
152+
match self {
153+
Block::Virtio(b) => b.force_userspace_bounce_buffers(),
154+
Block::VhostUser(b) => b.force_userspace_bounce_buffers(),
155+
}
156+
}
157+
158+
fn userspace_bounce_buffers(&self) -> bool {
159+
match self {
160+
Block::Virtio(b) => b.userspace_bounce_buffers(),
161+
Block::VhostUser(b) => b.userspace_bounce_buffers(),
162+
}
163+
}
164+
151165
fn device_type(&self) -> u32 {
152166
TYPE_BLOCK
153167
}

src/vmm/src/devices/virtio/block/vhost_user/device.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,14 @@ impl<T: VhostUserHandleBackend + Send + 'static> VirtioDevice for VhostUserBlock
294294
self.acked_features = acked_features;
295295
}
296296

297+
fn force_userspace_bounce_buffers(&mut self) {
298+
// Nothing Firecracker can do about this, the backend would need to do the bouncing
299+
}
300+
301+
fn userspace_bounce_buffers(&self) -> bool {
302+
false
303+
}
304+
297305
fn device_type(&self) -> u32 {
298306
TYPE_BLOCK
299307
}

src/vmm/src/devices/virtio/block/virtio/device.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,20 @@ impl VirtioDevice for VirtioBlock {
578578
self.acked_features = acked_features;
579579
}
580580

581+
fn force_userspace_bounce_buffers(&mut self) {
582+
match self.disk.file_engine {
583+
FileEngine::Async(_) => panic!("No idea how this is supposed to work for io_uring"),
584+
FileEngine::Sync(ref mut engine) => engine.start_bouncing(),
585+
}
586+
}
587+
588+
fn userspace_bounce_buffers(&self) -> bool {
589+
match self.disk.file_engine {
590+
FileEngine::Async(_) => false,
591+
FileEngine::Sync(ref engine) => engine.is_bouncing(),
592+
}
593+
}
594+
581595
fn device_type(&self) -> u32 {
582596
TYPE_BLOCK
583597
}

src/vmm/src/devices/virtio/block/virtio/io/sync_io.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::io::{Seek, SeekFrom, Write};
66

77
use vm_memory::{GuestMemoryError, ReadVolatile, WriteVolatile};
88

9-
use crate::vstate::memory::{GuestAddress, GuestMemory, GuestMemoryMmap};
9+
use crate::vstate::memory::{GuestAddress, GuestMemory, GuestMemoryMmap, MaybeBounce};
1010

1111
#[derive(Debug, thiserror::Error, displaydoc::Display)]
1212
pub enum SyncIoError {
@@ -22,25 +22,40 @@ pub enum SyncIoError {
2222

2323
#[derive(Debug)]
2424
pub struct SyncFileEngine {
25-
file: File,
25+
// 65536 is the largest buffer a linux guest will give us, empirically. Determined by
26+
// having `MaybeBounce` logging scenarios where the fixed size bounce buffer isn't sufficient.
27+
// Note that even if this assumption ever changes, the worse that'll happen is that we do
28+
// multiple roundtrips between guest memory and the bounce buffer, as MaybeBounce would
29+
// just chop larger reads/writes into chunks of 65k.
30+
file: MaybeBounce<File, { u16::MAX as usize + 1 }>,
2631
}
2732

2833
// SAFETY: `File` is send and ultimately a POD.
2934
unsafe impl Send for SyncFileEngine {}
3035

3136
impl SyncFileEngine {
3237
pub fn from_file(file: File) -> SyncFileEngine {
33-
SyncFileEngine { file }
38+
SyncFileEngine {
39+
file: MaybeBounce::new_persistent(file, false),
40+
}
3441
}
3542

3643
#[cfg(test)]
3744
pub fn file(&self) -> &File {
38-
&self.file
45+
&self.file.target
46+
}
47+
48+
pub fn start_bouncing(&mut self) {
49+
self.file.activate()
50+
}
51+
52+
pub fn is_bouncing(&self) -> bool {
53+
self.file.is_activated()
3954
}
4055

4156
/// Update the backing file of the engine
4257
pub fn update_file(&mut self, file: File) {
43-
self.file = file
58+
self.file.target = file
4459
}
4560

4661
pub fn read(
@@ -77,8 +92,8 @@ impl SyncFileEngine {
7792

7893
pub fn flush(&mut self) -> Result<(), SyncIoError> {
7994
// flush() first to force any cached data out of rust buffers.
80-
self.file.flush().map_err(SyncIoError::Flush)?;
95+
self.file.target.flush().map_err(SyncIoError::Flush)?;
8196
// Sync data out to physical media on host.
82-
self.file.sync_all().map_err(SyncIoError::SyncAll)
97+
self.file.target.sync_all().map_err(SyncIoError::SyncAll)
8398
}
8499
}

src/vmm/src/devices/virtio/block/virtio/persist.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::devices::virtio::TYPE_BLOCK;
1616
use crate::devices::virtio::block::persist::BlockConstructorArgs;
1717
use crate::devices::virtio::block::virtio::device::FileEngineType;
1818
use crate::devices::virtio::block::virtio::metrics::BlockMetricsPerDevice;
19-
use crate::devices::virtio::device::{DeviceState, IrqTrigger};
19+
use crate::devices::virtio::device::{DeviceState, IrqTrigger, VirtioDevice};
2020
use crate::devices::virtio::generated::virtio_blk::VIRTIO_BLK_F_RO;
2121
use crate::devices::virtio::persist::VirtioDeviceState;
2222
use crate::rate_limiter::RateLimiter;
@@ -127,7 +127,7 @@ impl Persist<'_> for VirtioBlock {
127127
capacity: disk_properties.nsectors.to_le(),
128128
};
129129

130-
Ok(VirtioBlock {
130+
let mut dev = VirtioBlock {
131131
avail_features,
132132
acked_features,
133133
config_space,
@@ -148,7 +148,13 @@ impl Persist<'_> for VirtioBlock {
148148
rate_limiter,
149149
is_io_engine_throttled: false,
150150
metrics: BlockMetricsPerDevice::alloc(state.id.clone()),
151-
})
151+
};
152+
153+
if state.virtio_state.bounce_in_userspace {
154+
dev.force_userspace_bounce_buffers()
155+
}
156+
157+
Ok(dev)
152158
}
153159
}
154160

src/vmm/src/devices/virtio/device.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ pub trait VirtioDevice: AsAny + Send {
102102
/// - self.avail_features() & self.acked_features() = self.get_acked_features()
103103
fn set_acked_features(&mut self, acked_features: u64);
104104

105+
/// Make the virtio device user userspace bounce buffers
106+
fn force_userspace_bounce_buffers(&mut self);
107+
108+
/// Whether this device is using userspace bounce buffers
109+
fn userspace_bounce_buffers(&self) -> bool;
110+
105111
/// Check if virtio device has negotiated given feature.
106112
fn has_feature(&self, feature: u64) -> bool {
107113
(self.acked_features() & (1 << feature)) != 0
@@ -259,6 +265,14 @@ pub(crate) mod tests {
259265
todo!()
260266
}
261267

268+
fn force_userspace_bounce_buffers(&mut self) {
269+
todo!()
270+
}
271+
272+
fn userspace_bounce_buffers(&self) -> bool {
273+
todo!()
274+
}
275+
262276
fn device_type(&self) -> u32 {
263277
todo!()
264278
}

src/vmm/src/devices/virtio/mmio.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,14 @@ pub(crate) mod tests {
423423
self.acked_features = acked_features;
424424
}
425425

426+
fn force_userspace_bounce_buffers(&mut self) {
427+
unimplemented!()
428+
}
429+
430+
fn userspace_bounce_buffers(&self) -> bool {
431+
false
432+
}
433+
426434
fn device_type(&self) -> u32 {
427435
123
428436
}

0 commit comments

Comments
 (0)