Skip to content

Commit 1273277

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 <[email protected]>
1 parent e2ed128 commit 1273277

File tree

20 files changed

+280
-33
lines changed

20 files changed

+280
-33
lines changed

src/vmm/src/device_manager/mmio.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,14 @@ mod tests {
604604
unimplemented!()
605605
}
606606

607+
fn force_userspace_bounce_buffers(&mut self) {
608+
todo!()
609+
}
610+
611+
fn userspace_bounce_buffers(&self) -> bool {
612+
todo!()
613+
}
614+
607615
fn device_type(&self) -> u32 {
608616
0
609617
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,14 @@ impl VirtioDevice for Balloon {
563563
self.avail_features |= 1 << VIRTIO_F_ACCESS_PLATFORM;
564564
}
565565

566+
fn force_userspace_bounce_buffers(&mut self) {
567+
// balloon device doesn't have a need for bounce buffers
568+
}
569+
570+
fn userspace_bounce_buffers(&self) -> bool {
571+
false
572+
}
573+
566574
fn device_type(&self) -> u32 {
567575
TYPE_BALLOON
568576
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,20 @@ impl VirtioDevice for Block {
155155
}
156156
}
157157

158+
fn force_userspace_bounce_buffers(&mut self) {
159+
match self {
160+
Block::Virtio(b) => b.force_userspace_bounce_buffers(),
161+
Block::VhostUser(b) => b.force_userspace_bounce_buffers(),
162+
}
163+
}
164+
165+
fn userspace_bounce_buffers(&self) -> bool {
166+
match self {
167+
Block::Virtio(b) => b.userspace_bounce_buffers(),
168+
Block::VhostUser(b) => b.userspace_bounce_buffers(),
169+
}
170+
}
171+
158172
fn device_type(&self) -> u32 {
159173
TYPE_BLOCK
160174
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,14 @@ impl<T: VhostUserHandleBackend + Send + 'static> VirtioDevice for VhostUserBlock
300300
self.avail_features |= 1 << VIRTIO_F_ACCESS_PLATFORM;
301301
}
302302

303+
fn force_userspace_bounce_buffers(&mut self) {
304+
// Nothing Firecracker can do about this, the backend would need to do the bouncing
305+
}
306+
307+
fn userspace_bounce_buffers(&self) -> bool {
308+
false
309+
}
310+
303311
fn device_type(&self) -> u32 {
304312
TYPE_BLOCK
305313
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,20 @@ impl VirtioDevice for VirtioBlock {
584584
self.avail_features |= 1 << VIRTIO_F_ACCESS_PLATFORM;
585585
}
586586

587+
fn force_userspace_bounce_buffers(&mut self) {
588+
match self.disk.file_engine {
589+
FileEngine::Async(_) => panic!("No idea how this is supposed to work for io_uring"),
590+
FileEngine::Sync(ref mut engine) => engine.start_bouncing(),
591+
}
592+
}
593+
594+
fn userspace_bounce_buffers(&self) -> bool {
595+
match self.disk.file_engine {
596+
FileEngine::Async(_) => false,
597+
FileEngine::Sync(ref engine) => engine.is_bouncing(),
598+
}
599+
}
600+
587601
fn device_type(&self) -> u32 {
588602
TYPE_BLOCK
589603
}

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

Lines changed: 18 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,36 @@ 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
26+
file: MaybeBounce<File, { u16::MAX as usize + 1 }>,
2627
}
2728

2829
// SAFETY: `File` is send and ultimately a POD.
2930
unsafe impl Send for SyncFileEngine {}
3031

3132
impl SyncFileEngine {
3233
pub fn from_file(file: File) -> SyncFileEngine {
33-
SyncFileEngine { file }
34+
SyncFileEngine {
35+
file: MaybeBounce::new_persistent(file, false),
36+
}
3437
}
3538

3639
#[cfg(test)]
3740
pub fn file(&self) -> &File {
38-
&self.file
41+
&self.file.target
42+
}
43+
44+
pub fn start_bouncing(&mut self) {
45+
self.file.should_bounce = true
46+
}
47+
48+
pub fn is_bouncing(&self) -> bool {
49+
self.file.should_bounce
3950
}
4051

4152
/// Update the backing file of the engine
4253
pub fn update_file(&mut self, file: File) {
43-
self.file = file
54+
self.file.target = file
4455
}
4556

4657
pub fn read(
@@ -77,8 +88,8 @@ impl SyncFileEngine {
7788

7889
pub fn flush(&mut self) -> Result<(), SyncIoError> {
7990
// flush() first to force any cached data out of rust buffers.
80-
self.file.flush().map_err(SyncIoError::Flush)?;
91+
self.file.target.flush().map_err(SyncIoError::Flush)?;
8192
// Sync data out to physical media on host.
82-
self.file.sync_all().map_err(SyncIoError::SyncAll)
93+
self.file.target.sync_all().map_err(SyncIoError::SyncAll)
8394
}
8495
}

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
@@ -105,6 +105,12 @@ pub trait VirtioDevice: AsAny + Send {
105105
/// Make the virtio device offer the VIRTIO_F_ACCESS_PLATFORM feature
106106
fn force_swiotlb(&mut self);
107107

108+
/// Make the virtio device user userspace bounce buffers
109+
fn force_userspace_bounce_buffers(&mut self);
110+
111+
/// Whether this device is using userspace bounce buffers
112+
fn userspace_bounce_buffers(&self) -> bool;
113+
108114
/// Check if virtio device has negotiated given feature.
109115
fn has_feature(&self, feature: u64) -> bool {
110116
(self.acked_features() & (1 << feature)) != 0
@@ -266,6 +272,14 @@ pub(crate) mod tests {
266272
unimplemented!()
267273
}
268274

275+
fn force_userspace_bounce_buffers(&mut self) {
276+
todo!()
277+
}
278+
279+
fn userspace_bounce_buffers(&self) -> bool {
280+
todo!()
281+
}
282+
269283
fn device_type(&self) -> u32 {
270284
todo!()
271285
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,14 @@ pub(crate) mod tests {
427427
unimplemented!()
428428
}
429429

430+
fn force_userspace_bounce_buffers(&mut self) {
431+
todo!()
432+
}
433+
434+
fn userspace_bounce_buffers(&self) -> bool {
435+
todo!()
436+
}
437+
430438
fn device_type(&self) -> u32 {
431439
123
432440
}

0 commit comments

Comments
 (0)