Skip to content

Commit 540820c

Browse files
committed
feat(virtio-pmem): add device to the Vmm
Add methods to attach virtio-pmem devices to Vmm. Add methods to create KVM memory slot for virtio-pmem devices. Signed-off-by: Egor Lazarchuk <[email protected]>
1 parent 2fc6736 commit 540820c

File tree

2 files changed

+137
-4
lines changed

2 files changed

+137
-4
lines changed

src/vmm/src/builder.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use crate::devices::acpi::vmgenid::VmGenIdError;
3333
use crate::devices::virtio::balloon::Balloon;
3434
use crate::devices::virtio::block::device::Block;
3535
use crate::devices::virtio::net::Net;
36+
use crate::devices::virtio::pmem::device::Pmem;
3637
use crate::devices::virtio::rng::Entropy;
3738
use crate::devices::virtio::vsock::{Vsock, VsockUnixBackend};
3839
#[cfg(feature = "gdb")]
@@ -68,6 +69,8 @@ pub enum StartMicrovmError {
6869
CreateGuestConfig(#[from] GuestConfigError),
6970
/// Cannot create network device: {0}
7071
CreateNetDevice(crate::devices::virtio::net::NetError),
72+
/// Cannot create pmem device: {0}
73+
CreatePmemDevice(#[from] crate::devices::virtio::pmem::device::PmemError),
7174
/// Cannot create RateLimiter: {0}
7275
CreateRateLimiter(io::Error),
7376
/// Error creating legacy device: {0}
@@ -219,6 +222,13 @@ pub fn build_microvm_for_boot(
219222
vm_resources.net_builder.iter(),
220223
event_manager,
221224
)?;
225+
attach_pmem_devices(
226+
&mut device_manager,
227+
&vm,
228+
&mut boot_cmdline,
229+
vm_resources.pmem.devices.iter(),
230+
event_manager,
231+
)?;
222232

223233
if let Some(unix_vsock) = vm_resources.vsock.get() {
224234
attach_unixsock_vsock_device(
@@ -609,6 +619,34 @@ fn attach_net_devices<'a, I: Iterator<Item = &'a Arc<Mutex<Net>>> + Debug>(
609619
Ok(())
610620
}
611621

622+
fn attach_pmem_devices<'a, I: Iterator<Item = &'a Arc<Mutex<Pmem>>> + Debug>(
623+
device_manager: &mut DeviceManager,
624+
vm: &Arc<Vm>,
625+
cmdline: &mut LoaderKernelCmdline,
626+
pmem_devices: I,
627+
event_manager: &mut EventManager,
628+
) -> Result<(), StartMicrovmError> {
629+
for (i, device) in pmem_devices.enumerate() {
630+
let id = {
631+
let mut locked_dev = device.lock().expect("Poisoned lock");
632+
if locked_dev.config.root_device {
633+
cmdline.insert_str(format!("root=/dev/pmem{i}"))?;
634+
match locked_dev.config.read_only {
635+
true => cmdline.insert_str("ro")?,
636+
false => cmdline.insert_str("rw")?,
637+
}
638+
}
639+
locked_dev.alloc_region(vm.as_ref());
640+
locked_dev.set_mem_region(vm.as_ref())?;
641+
locked_dev.config.id.to_string()
642+
};
643+
644+
event_manager.add_subscriber(device.clone());
645+
device_manager.attach_virtio_device(vm, id, device.clone(), cmdline, false)?;
646+
}
647+
Ok(())
648+
}
649+
612650
fn attach_unixsock_vsock_device(
613651
device_manager: &mut DeviceManager,
614652
vm: &Arc<Vm>,
@@ -655,6 +693,7 @@ pub(crate) mod tests {
655693
use crate::vmm_config::drive::{BlockBuilder, BlockDeviceConfig};
656694
use crate::vmm_config::entropy::{EntropyDeviceBuilder, EntropyDeviceConfig};
657695
use crate::vmm_config::net::{NetBuilder, NetworkInterfaceConfig};
696+
use crate::vmm_config::pmem::{PmemBuilder, PmemConfig};
658697
use crate::vmm_config::vsock::tests::default_config;
659698
use crate::vmm_config::vsock::{VsockBuilder, VsockDeviceConfig};
660699
use crate::vstate::vm::tests::setup_vm_with_memory;
@@ -875,6 +914,34 @@ pub(crate) mod tests {
875914
);
876915
}
877916

917+
pub(crate) fn insert_pmem_devices(
918+
vmm: &mut Vmm,
919+
cmdline: &mut Cmdline,
920+
event_manager: &mut EventManager,
921+
configs: Vec<PmemConfig>,
922+
) -> Vec<TempFile> {
923+
let mut builder = PmemBuilder::default();
924+
let mut files = Vec::new();
925+
for mut config in configs {
926+
let tmp_file = TempFile::new().unwrap();
927+
tmp_file.as_file().set_len(0x20_0000).unwrap();
928+
let tmp_file_path = tmp_file.as_path().to_str().unwrap().to_string();
929+
files.push(tmp_file);
930+
config.path_on_host = tmp_file_path;
931+
builder.build(config, false).unwrap();
932+
}
933+
934+
attach_pmem_devices(
935+
&mut vmm.device_manager,
936+
&vmm.vm,
937+
cmdline,
938+
builder.devices.iter(),
939+
event_manager,
940+
)
941+
.unwrap();
942+
files
943+
}
944+
878945
#[cfg(target_arch = "x86_64")]
879946
pub(crate) fn insert_vmgenid_device(vmm: &mut Vmm) {
880947
vmm.device_manager
@@ -1122,6 +1189,28 @@ pub(crate) mod tests {
11221189
}
11231190
}
11241191

1192+
#[test]
1193+
fn test_attach_pmem_devices() {
1194+
let mut event_manager = EventManager::new().expect("Unable to create EventManager");
1195+
1196+
let id = String::from("root");
1197+
let configs = vec![PmemConfig {
1198+
id: id.clone(),
1199+
path_on_host: "".into(),
1200+
root_device: true,
1201+
read_only: true,
1202+
}];
1203+
let mut vmm = default_vmm();
1204+
let mut cmdline = default_kernel_cmdline();
1205+
_ = insert_pmem_devices(&mut vmm, &mut cmdline, &mut event_manager, configs);
1206+
assert!(cmdline_contains(&cmdline, "root=/dev/pmem0 ro"));
1207+
assert!(
1208+
vmm.device_manager
1209+
.get_virtio_device(virtio_ids::VIRTIO_ID_PMEM, id.as_str())
1210+
.is_some()
1211+
);
1212+
}
1213+
11251214
#[test]
11261215
fn test_attach_boot_timer_device() {
11271216
let mut vmm = default_vmm();

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

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
use std::fs::{File, OpenOptions};
5-
use std::ops::Deref;
5+
use std::ops::{Deref, DerefMut};
66
use std::os::fd::AsRawFd;
77
use std::sync::{Arc, Mutex};
88

9+
use kvm_bindings::{KVM_MEM_READONLY, kvm_userspace_memory_region};
910
use kvm_ioctls::VmFd;
11+
use serde::{Deserialize, Serialize};
12+
use vm_allocator::AllocPolicy;
1013
use vm_memory::mmap::{MmapRegionBuilder, MmapRegionError};
1114
use vm_memory::{GuestAddress, GuestMemoryError};
1215
use vmm_sys_util::eventfd::EventFd;
@@ -15,19 +18,22 @@ use crate::devices::virtio::ActivateError;
1518
use crate::devices::virtio::device::{ActiveState, DeviceState, VirtioDevice};
1619
use crate::devices::virtio::generated::virtio_config::VIRTIO_F_VERSION_1;
1720
use crate::devices::virtio::generated::virtio_ids::VIRTIO_ID_PMEM;
21+
use crate::devices::virtio::pmem::PMEM_QUEUE_SIZE;
1822
use crate::devices::virtio::pmem::metrics::{PmemMetrics, PmemMetricsPerDevice};
1923
use crate::devices::virtio::queue::{DescriptorChain, InvalidAvailIdx, Queue, QueueError};
2024
use crate::devices::virtio::transport::{VirtioInterrupt, VirtioInterruptType};
21-
use crate::impl_device_type;
2225
use crate::logger::{IncMetric, error};
2326
use crate::utils::{align_up, u64_to_usize};
2427
use crate::vmm_config::pmem::PmemConfig;
2528
use crate::vstate::memory::{ByteValued, Bytes, GuestMemoryMmap, GuestMmapRegion};
26-
27-
pub const PMEM_QUEUE_SIZE: u16 = 256;
29+
use crate::{Vm, impl_device_type};
2830

2931
#[derive(Debug, thiserror::Error, displaydoc::Display)]
3032
pub enum PmemError {
33+
/// Cannot set the memory regions: {0}
34+
SetUserMemoryRegion(kvm_ioctls::Error),
35+
/// Unablet to allocate a KVM slot for the device
36+
NoKvmSlotAvailable,
3137
/// Error accessing backing file: {0}
3238
BackingFile(std::io::Error),
3339
/// Error backing file size is 0
@@ -192,6 +198,44 @@ impl Pmem {
192198
Ok((file, file_len, mmap_ptr as u64, mmap_len))
193199
}
194200

201+
/// Allocater memory in past_mmio64 memory region
202+
pub fn alloc_region(&mut self, vm: &Vm) {
203+
let mut resource_allocator_lock = vm.resource_allocator();
204+
let resource_allocator = resource_allocator_lock.deref_mut();
205+
let addr = resource_allocator
206+
.past_mmio64_memory
207+
.allocate(
208+
self.config_space.size,
209+
Pmem::ALIGNMENT,
210+
AllocPolicy::FirstMatch,
211+
)
212+
.unwrap();
213+
self.config_space.start = addr.start();
214+
}
215+
216+
/// Set user memory region in KVM
217+
pub fn set_mem_region(&mut self, vm: &Vm) -> Result<(), PmemError> {
218+
let next_slot = vm.next_kvm_slot().ok_or(PmemError::NoKvmSlotAvailable)?;
219+
let memory_region = kvm_userspace_memory_region {
220+
slot: next_slot,
221+
guest_phys_addr: self.config_space.start,
222+
memory_size: self.config_space.size,
223+
userspace_addr: self.mmap_ptr,
224+
flags: if self.config.read_only {
225+
KVM_MEM_READONLY
226+
} else {
227+
0
228+
},
229+
};
230+
// SAFETY: All aruments are correct
231+
unsafe {
232+
vm.fd()
233+
.set_user_memory_region(memory_region)
234+
.map_err(PmemError::SetUserMemoryRegion)?;
235+
}
236+
Ok(())
237+
}
238+
195239
fn handle_queue(&mut self) -> Result<(), PmemError> {
196240
// This is safe since we checked in the event handler that the device is activated.
197241
let active_state = self.device_state.active_state().unwrap();

0 commit comments

Comments
 (0)