Skip to content

Commit d66c7ba

Browse files
committed
use userspace bounce buffers if no swiotlb is configured
Mark vhost-user and async block engine as incompatible, as for vhost-user-blk, we would need to communicate the need for bounce buffers to the backend somehow, and for the async block engine we would need to somehow keep the bounce buffers around until io_uring finishes requests (which is not impossible, but complicated and not needed for now). Signed-off-by: Patrick Roy <[email protected]>
1 parent 1273277 commit d66c7ba

File tree

7 files changed

+96
-54
lines changed

7 files changed

+96
-54
lines changed

src/vmm/src/builder.rs

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -321,16 +321,24 @@ pub fn build_microvm_for_boot(
321321
&mut boot_cmdline,
322322
vm_resources.block.devices.iter(),
323323
event_manager,
324+
secret_free,
324325
)?;
325326
attach_net_devices(
326327
&mut vmm,
327328
&mut boot_cmdline,
328329
vm_resources.net_builder.iter(),
329330
event_manager,
331+
secret_free,
330332
)?;
331333

332334
if let Some(unix_vsock) = vm_resources.vsock.get() {
333-
attach_unixsock_vsock_device(&mut vmm, &mut boot_cmdline, unix_vsock, event_manager)?;
335+
attach_unixsock_vsock_device(
336+
&mut vmm,
337+
&mut boot_cmdline,
338+
unix_vsock,
339+
event_manager,
340+
secret_free,
341+
)?;
334342
}
335343

336344
if let Some(entropy) = vm_resources.entropy.get() {
@@ -707,14 +715,19 @@ fn attach_virtio_device<T: 'static + VirtioDevice + MutEventSubscriber + Debug>(
707715
device: Arc<Mutex<T>>,
708716
cmdline: &mut LoaderKernelCmdline,
709717
is_vhost_user: bool,
718+
needs_bouncing: bool,
710719
) -> Result<(), MmioError> {
711720
event_manager.add_subscriber(device.clone());
712721

713722
// We have to enable swiotlb as part of the boot process, because the device objects
714723
// themselves are created when the corresponding PUT API calls are made, and at that
715724
// point we don't know yet whether swiotlb should be enabled or not.
716-
if vmm.vm.has_swiotlb() {
717-
device.lock().unwrap().force_swiotlb();
725+
if needs_bouncing {
726+
if vmm.vm.has_swiotlb() {
727+
device.lock().unwrap().force_swiotlb();
728+
} else {
729+
device.lock().unwrap().force_userspace_bounce_buffers();
730+
}
718731
}
719732

720733
// The device mutex mustn't be locked here otherwise it will deadlock.
@@ -772,6 +785,7 @@ fn attach_entropy_device(
772785
entropy_device.clone(),
773786
cmdline,
774787
false,
788+
false,
775789
)
776790
}
777791

@@ -780,6 +794,7 @@ fn attach_block_devices<'a, I: Iterator<Item = &'a Arc<Mutex<Block>>> + Debug>(
780794
cmdline: &mut LoaderKernelCmdline,
781795
blocks: I,
782796
event_manager: &mut EventManager,
797+
needs_bouncing: bool,
783798
) -> Result<(), StartMicrovmError> {
784799
for block in blocks {
785800
let (id, is_vhost_user) = {
@@ -804,6 +819,7 @@ fn attach_block_devices<'a, I: Iterator<Item = &'a Arc<Mutex<Block>>> + Debug>(
804819
block.clone(),
805820
cmdline,
806821
is_vhost_user,
822+
needs_bouncing,
807823
)?;
808824
}
809825
Ok(())
@@ -814,11 +830,20 @@ fn attach_net_devices<'a, I: Iterator<Item = &'a Arc<Mutex<Net>>> + Debug>(
814830
cmdline: &mut LoaderKernelCmdline,
815831
net_devices: I,
816832
event_manager: &mut EventManager,
833+
needs_bouncing: bool,
817834
) -> Result<(), StartMicrovmError> {
818835
for net_device in net_devices {
819836
let id = net_device.lock().expect("Poisoned lock").id().clone();
820837
// The device mutex mustn't be locked here otherwise it will deadlock.
821-
attach_virtio_device(event_manager, vmm, id, net_device.clone(), cmdline, false)?;
838+
attach_virtio_device(
839+
event_manager,
840+
vmm,
841+
id,
842+
net_device.clone(),
843+
cmdline,
844+
false,
845+
needs_bouncing,
846+
)?;
822847
}
823848
Ok(())
824849
}
@@ -828,10 +853,19 @@ fn attach_unixsock_vsock_device(
828853
cmdline: &mut LoaderKernelCmdline,
829854
unix_vsock: &Arc<Mutex<Vsock<VsockUnixBackend>>>,
830855
event_manager: &mut EventManager,
856+
needs_bouncing: bool,
831857
) -> Result<(), MmioError> {
832858
let id = String::from(unix_vsock.lock().expect("Poisoned lock").id());
833859
// The device mutex mustn't be locked here otherwise it will deadlock.
834-
attach_virtio_device(event_manager, vmm, id, unix_vsock.clone(), cmdline, false)
860+
attach_virtio_device(
861+
event_manager,
862+
vmm,
863+
id,
864+
unix_vsock.clone(),
865+
cmdline,
866+
false,
867+
needs_bouncing,
868+
)
835869
}
836870

837871
fn attach_balloon_device(
@@ -842,7 +876,15 @@ fn attach_balloon_device(
842876
) -> Result<(), MmioError> {
843877
let id = String::from(balloon.lock().expect("Poisoned lock").id());
844878
// The device mutex mustn't be locked here otherwise it will deadlock.
845-
attach_virtio_device(event_manager, vmm, id, balloon.clone(), cmdline, false)
879+
attach_virtio_device(
880+
event_manager,
881+
vmm,
882+
id,
883+
balloon.clone(),
884+
cmdline,
885+
false,
886+
false,
887+
)
846888
}
847889

848890
// Adds `O_NONBLOCK` to the stdout flags.
@@ -1018,6 +1060,7 @@ pub(crate) mod tests {
10181060
cmdline,
10191061
block_dev_configs.devices.iter(),
10201062
event_manager,
1063+
false,
10211064
)
10221065
.unwrap();
10231066
block_files
@@ -1032,7 +1075,7 @@ pub(crate) mod tests {
10321075
let mut net_builder = NetBuilder::new();
10331076
net_builder.build(net_config).unwrap();
10341077

1035-
let res = attach_net_devices(vmm, cmdline, net_builder.iter(), event_manager);
1078+
let res = attach_net_devices(vmm, cmdline, net_builder.iter(), event_manager, false);
10361079
res.unwrap();
10371080
}
10381081

@@ -1053,7 +1096,7 @@ pub(crate) mod tests {
10531096
Arc::new(Mutex::new(mmds)),
10541097
);
10551098

1056-
attach_net_devices(vmm, cmdline, net_builder.iter(), event_manager).unwrap();
1099+
attach_net_devices(vmm, cmdline, net_builder.iter(), event_manager, false).unwrap();
10571100
}
10581101

10591102
pub(crate) fn insert_vsock_device(
@@ -1066,7 +1109,7 @@ pub(crate) mod tests {
10661109
let vsock = VsockBuilder::create_unixsock_vsock(vsock_config).unwrap();
10671110
let vsock = Arc::new(Mutex::new(vsock));
10681111

1069-
attach_unixsock_vsock_device(vmm, cmdline, &vsock, event_manager).unwrap();
1112+
attach_unixsock_vsock_device(vmm, cmdline, &vsock, event_manager, false).unwrap();
10701113

10711114
assert!(
10721115
vmm.mmio_device_manager

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ impl<T: VhostUserHandleBackend + Send + 'static> VirtioDevice for VhostUserBlock
302302

303303
fn force_userspace_bounce_buffers(&mut self) {
304304
// Nothing Firecracker can do about this, the backend would need to do the bouncing
305+
panic!("vhost-user-blk is incompatible with userspace bounce buffers")
305306
}
306307

307308
fn userspace_bounce_buffers(&self) -> bool {

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,9 @@ impl VirtioDevice for VirtioBlock {
586586

587587
fn force_userspace_bounce_buffers(&mut self) {
588588
match self.disk.file_engine {
589-
FileEngine::Async(_) => panic!("No idea how this is supposed to work for io_uring"),
589+
FileEngine::Async(_) => {
590+
panic!("async engine is incompatible with userspace bounce buffers")
591+
}
590592
FileEngine::Sync(ref mut engine) => engine.start_bouncing(),
591593
}
592594
}

src/vmm/src/resources.rs

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use serde::{Deserialize, Serialize};
1010

1111
use crate::cpu_config::templates::CustomCpuTemplate;
1212
use crate::device_manager::persist::SharedDeviceType;
13+
use crate::devices::virtio::block::device::Block;
1314
use crate::logger::info;
1415
use crate::mmds;
1516
use crate::mmds::data_store::{Mmds, MmdsVersion};
@@ -111,14 +112,6 @@ pub struct VmResources {
111112
}
112113

113114
impl VmResources {
114-
/// Whether this [`VmResources`] object contains any devices that require host kernel access
115-
/// into guest memory.
116-
pub fn has_any_io_devices(&self) -> bool {
117-
!self.block.devices.is_empty()
118-
|| self.vsock.get().is_some()
119-
|| self.net_builder.iter().next().is_some()
120-
}
121-
122115
/// Configures Vmm resources as described by the `config_json` param.
123116
pub fn from_json(
124117
config_json: &str,
@@ -270,16 +263,6 @@ impl VmResources {
270263
return Err(MachineConfigError::IncompatibleBalloonSize);
271264
}
272265

273-
if self.has_any_io_devices()
274-
&& self.machine_config.mem_config.secret_free
275-
&& !self.swiotlb_used()
276-
{
277-
return Err(MachineConfigError::Incompatible(
278-
"secret freedom",
279-
"I/O without swiotlb",
280-
));
281-
}
282-
283266
if self.balloon.get().is_some() && updated.huge_pages != HugePageConfig::None {
284267
return Err(MachineConfigError::Incompatible(
285268
"balloon device",
@@ -292,6 +275,22 @@ impl VmResources {
292275
"secret freedom",
293276
));
294277
}
278+
if !self.swiotlb_used() && updated.mem_config.secret_free {
279+
if self.vhost_user_devices_used() {
280+
return Err(MachineConfigError::Incompatible(
281+
"vhost-user devices",
282+
"userspace bounce buffers",
283+
));
284+
}
285+
286+
if self.async_block_engine_used() {
287+
return Err(MachineConfigError::Incompatible(
288+
"async block engine",
289+
"userspace bounce buffers",
290+
));
291+
}
292+
}
293+
295294
self.machine_config = updated;
296295

297296
Ok(())
@@ -377,13 +376,18 @@ impl VmResources {
377376
&mut self,
378377
block_device_config: BlockDeviceConfig,
379378
) -> Result<(), DriveError> {
380-
if self.has_any_io_devices()
381-
&& self.machine_config.mem_config.secret_free
382-
&& !self.swiotlb_used()
383-
{
384-
return Err(DriveError::SecretFreeWithoutSwiotlb);
379+
if self.machine_config.mem_config.secret_free && !self.swiotlb_used() {
380+
if block_device_config.file_engine_type == Some(FileEngineType::Async) {
381+
return Err(DriveError::IncompatibleWithUserspaceBounceBuffers(
382+
"async file engine",
383+
));
384+
}
385+
if block_device_config.socket.is_some() {
386+
return Err(DriveError::IncompatibleWithUserspaceBounceBuffers(
387+
"vhost-user-blk",
388+
));
389+
}
385390
}
386-
387391
self.block.insert(block_device_config)
388392
}
389393

@@ -392,26 +396,12 @@ impl VmResources {
392396
&mut self,
393397
body: NetworkInterfaceConfig,
394398
) -> Result<(), NetworkInterfaceError> {
395-
if self.has_any_io_devices()
396-
&& self.machine_config.mem_config.secret_free
397-
&& !self.swiotlb_used()
398-
{
399-
return Err(NetworkInterfaceError::SecretFreeWithoutSwiotlb);
400-
}
401-
402399
let _ = self.net_builder.build(body)?;
403400
Ok(())
404401
}
405402

406403
/// Sets a vsock device to be attached when the VM starts.
407404
pub fn set_vsock_device(&mut self, config: VsockDeviceConfig) -> Result<(), VsockConfigError> {
408-
if self.has_any_io_devices()
409-
&& self.machine_config.mem_config.secret_free
410-
&& !self.swiotlb_used()
411-
{
412-
return Err(VsockConfigError::SecretFreeWithoutSwiotlb);
413-
}
414-
415405
self.vsock.insert(config)
416406
}
417407

@@ -505,6 +495,16 @@ impl VmResources {
505495
.any(|b| b.lock().expect("Poisoned lock").is_vhost_user())
506496
}
507497

498+
fn async_block_engine_used(&self) -> bool {
499+
self.block
500+
.devices
501+
.iter()
502+
.any(|b| match &*b.lock().unwrap() {
503+
Block::Virtio(b) => b.file_engine_type() == FileEngineType::Async,
504+
Block::VhostUser(_) => false,
505+
})
506+
}
507+
508508
/// The size of the swiotlb region requested, in MiB
509509
#[cfg(target_arch = "aarch64")]
510510
pub fn swiotlb_size(&self) -> usize {

src/vmm/src/vmm_config/drive.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ pub enum DriveError {
2424
DeviceUpdate(VmmError),
2525
/// A root block device already exists!
2626
RootBlockDeviceAlreadyAdded,
27-
/// A block device was added to a secret free VM that doesnt have a swiotlb region.
28-
SecretFreeWithoutSwiotlb,
27+
/// {0} is incompatible with userspace bounce buffers.
28+
IncompatibleWithUserspaceBounceBuffers(&'static str),
2929
}
3030

3131
/// Use this structure to set up the Block Device before booting the kernel.

src/vmm/src/vmm_config/net.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,6 @@ pub enum NetworkInterfaceError {
7171
GuestMacAddressInUse(String),
7272
/// Cannot open/create the tap device: {0}
7373
OpenTap(#[from] TapError),
74-
/// A net device was added to a secret free VM that doesnt have a swiotlb region.
75-
SecretFreeWithoutSwiotlb,
7674
}
7775

7876
/// Builder for a list of network devices.

src/vmm/src/vmm_config/vsock.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ pub enum VsockConfigError {
1717
CreateVsockBackend(VsockUnixBackendError),
1818
/// Cannot create vsock device: {0}
1919
CreateVsockDevice(VsockError),
20-
/// A vsock device was added to a secret free VM that doesnt have a swiotlb region.
21-
SecretFreeWithoutSwiotlb,
2220
}
2321

2422
/// This struct represents the strongly typed equivalent of the json body

0 commit comments

Comments
 (0)