Skip to content

Commit be45027

Browse files
committed
Remove Inventory mechanism
The Inventory abstraction in propolis-lib has outlived its necessity. Created initially to keep devices in scope after VM initialization, it was somewhat cumbersome to deal with, and was providing more friction that value when it came to accessing the contained Entity bits. With its removal, the Instance abstraction can go as well, since it was simply holding the Machine and the Inventory together. In this new world, propolis-lib consumers are left to hold Lifecycle (formerly Entity) trait objects in whatever way seems appropriate to them. With the Inventory gone, the parent-child relationships possible through the former Entity trait are also on the chopping block. The 440FX/PIIX4 chipset devices have been rearranged to more accurately reflect what is present in "real" devices.
1 parent 4902d82 commit be45027

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1195
-1864
lines changed

bin/propolis-server/src/lib/initializer.rs

+178-147
Large diffs are not rendered by default.

bin/propolis-server/src/lib/migrate/destination.rs

+11-16
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44

55
use bitvec::prelude as bv;
66
use futures::{SinkExt, StreamExt};
7-
use propolis::common::{GuestAddr, PAGE_SIZE};
8-
use propolis::inventory::Entity;
7+
use propolis::common::{GuestAddr, Lifecycle, PAGE_SIZE};
98
use propolis::migrate::{
109
MigrateCtx, MigrateStateError, Migrator, PayloadOffer, PayloadOffers,
1110
};
@@ -320,19 +319,18 @@ impl<T: AsyncRead + AsyncWrite + Unpin + Send> DestinationProtocol<T> {
320319
info!(self.log(), "Devices: {devices:#?}");
321320

322321
{
323-
let instance_guard = self.vm_controller.instance().lock();
324-
let inv = instance_guard.inventory();
325-
let migrate_ctx = MigrateCtx {
326-
mem: &instance_guard.machine().acc_mem.access().unwrap(),
327-
};
322+
let machine = self.vm_controller.machine();
323+
let migrate_ctx =
324+
MigrateCtx { mem: &machine.acc_mem.access().unwrap() };
328325
for device in devices {
329326
info!(
330327
self.log(),
331328
"Applying state to device {}", device.instance_name
332329
);
333330

334-
let target = inv
335-
.get_by_name(&device.instance_name)
331+
let target = self
332+
.vm_controller
333+
.device_by_name(&device.instance_name)
336334
.ok_or_else(|| {
337335
MigrateError::UnknownDevice(
338336
device.instance_name.clone(),
@@ -373,10 +371,7 @@ impl<T: AsyncRead + AsyncWrite + Unpin + Send> DestinationProtocol<T> {
373371

374372
// Take a snapshot of the host hrtime/wall clock time, then adjust
375373
// time data appropriately.
376-
let vmm_hdl = {
377-
let instance_guard = self.vm_controller.instance().lock();
378-
&instance_guard.machine().hdl.clone()
379-
};
374+
let vmm_hdl = &self.vm_controller.machine().hdl.clone();
380375
let (dst_hrt, dst_wc) = vmm::time::host_time_snapshot(vmm_hdl)
381376
.map_err(|e| {
382377
MigrateError::TimeData(format!(
@@ -451,7 +446,7 @@ impl<T: AsyncRead + AsyncWrite + Unpin + Send> DestinationProtocol<T> {
451446

452447
fn import_device(
453448
&self,
454-
target: &Arc<dyn Entity>,
449+
target: &Arc<dyn Lifecycle>,
455450
device: &Device,
456451
migrate_ctx: &MigrateCtx,
457452
) -> Result<(), MigrateError> {
@@ -644,8 +639,8 @@ impl<T: AsyncRead + AsyncWrite + Unpin + Send> DestinationProtocol<T> {
644639
addr: GuestAddr,
645640
buf: &[u8],
646641
) -> Result<(), MigrateError> {
647-
let instance_guard = self.vm_controller.instance().lock();
648-
let memctx = instance_guard.machine().acc_mem.access().unwrap();
642+
let machine = self.vm_controller.machine();
643+
let memctx = machine.acc_mem.access().unwrap();
649644
let len = buf.len();
650645
memctx.write_from(addr, buf, len);
651646
Ok(())

bin/propolis-server/src/lib/migrate/source.rs

+15-21
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
use futures::{SinkExt, StreamExt};
66
use propolis::common::{GuestAddr, PAGE_SIZE};
7-
use propolis::inventory::Order;
87
use propolis::migrate::{
98
MigrateCtx, MigrateStateError, Migrator, PayloadOutputs,
109
};
@@ -339,24 +338,23 @@ impl<T: AsyncRead + AsyncWrite + Unpin + Send> SourceProtocol<T> {
339338
self.update_state(MigrationState::Device).await;
340339
let mut device_states = vec![];
341340
{
342-
let instance_guard = self.vm_controller.instance().lock();
343-
let migrate_ctx = MigrateCtx {
344-
mem: &instance_guard.machine().acc_mem.access().unwrap(),
345-
};
341+
let machine = self.vm_controller.machine();
342+
let migrate_ctx =
343+
MigrateCtx { mem: &machine.acc_mem.access().unwrap() };
346344

347345
// Collect together the serialized state for all the devices
348-
instance_guard.inventory().for_each_node(Order::Pre, |_, rec| {
349-
let entity = rec.entity();
346+
self.vm_controller.for_each_device_fallible(|name, devop| {
350347
let mut dev = Device {
351-
instance_name: rec.name().to_owned(),
348+
instance_name: name.to_string(),
352349
payload: Vec::new(),
353350
};
354-
match entity.migrate() {
351+
match devop.migrate() {
355352
Migrator::NonMigratable => {
356353
error!(self.log(),
357354
"Can't migrate instance with non-migratable device ({})",
358-
rec.name());
359-
return Err(MigrateError::DeviceState(MigrateStateError::NonMigratable.to_string()));
355+
name);
356+
return Err(MigrateError::DeviceState(
357+
MigrateStateError::NonMigratable.to_string()));
360358
},
361359
// No device state needs to be trasmitted for 'Empty' devices
362360
Migrator::Empty => {},
@@ -403,10 +401,7 @@ impl<T: AsyncRead + AsyncWrite + Unpin + Send> SourceProtocol<T> {
403401

404402
// Read and send over the time data
405403
async fn time_data(&mut self) -> Result<(), MigrateError> {
406-
let vmm_hdl = {
407-
let instance_guard = self.vm_controller.instance().lock();
408-
&instance_guard.machine().hdl.clone()
409-
};
404+
let vmm_hdl = &self.vm_controller.machine().hdl.clone();
410405
let vm_time_data =
411406
vmm::time::export_time_data(vmm_hdl).map_err(|e| {
412407
MigrateError::TimeData(format!(
@@ -547,8 +542,8 @@ impl<T: AsyncRead + AsyncWrite + Unpin + Send> SourceProtocol<T> {
547542
async fn vmm_ram_bounds(
548543
&mut self,
549544
) -> Result<RangeInclusive<GuestAddr>, MigrateError> {
550-
let instance_guard = self.vm_controller.instance().lock();
551-
let memctx = instance_guard.machine().acc_mem.access().unwrap();
545+
let machine = self.vm_controller.machine();
546+
let memctx = machine.acc_mem.access().unwrap();
552547
memctx.mem_bounds().ok_or(MigrateError::InvalidInstanceState)
553548
}
554549

@@ -557,8 +552,7 @@ impl<T: AsyncRead + AsyncWrite + Unpin + Send> SourceProtocol<T> {
557552
start_gpa: GuestAddr,
558553
bits: &mut [u8],
559554
) -> Result<(), MigrateError> {
560-
let instance_guard = self.vm_controller.instance().lock();
561-
instance_guard
555+
self.vm_controller
562556
.machine()
563557
.hdl
564558
.track_dirty_pages(start_gpa.0, bits)
@@ -570,8 +564,8 @@ impl<T: AsyncRead + AsyncWrite + Unpin + Send> SourceProtocol<T> {
570564
addr: GuestAddr,
571565
buf: &mut [u8],
572566
) -> Result<(), MigrateError> {
573-
let instance_guard = self.vm_controller.instance().lock();
574-
let memctx = instance_guard.machine().acc_mem.access().unwrap();
567+
let machine = self.vm_controller.machine();
568+
let memctx = machine.acc_mem.access().unwrap();
575569
let len = buf.len();
576570
memctx.direct_read_into(addr, buf, len);
577571
Ok(())

bin/propolis-server/src/lib/server.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ use crate::spec::{ServerSpecBuilder, ServerSpecBuilderError};
4646
use crate::vm::VmController;
4747
use crate::vnc::PropolisVncServer;
4848

49+
pub(crate) type DeviceMap =
50+
BTreeMap<String, Arc<dyn propolis::common::Lifecycle>>;
51+
pub(crate) type BlockBackendMap =
52+
BTreeMap<String, Arc<dyn propolis::block::Backend>>;
4953
pub(crate) type CrucibleBackendMap =
5054
BTreeMap<uuid::Uuid, Arc<propolis::block::CrucibleBackend>>;
5155

@@ -529,17 +533,14 @@ async fn instance_ensure_common(
529533
let vnc_fb = crate::vnc::RamFb::new(fb_spec);
530534

531535
// Get a reference to the PS2 controller so that we can pass keyboard input.
532-
let ps2ctrl = vm.ps2ctrl().unwrap();
536+
let ps2ctrl = vm.ps2ctrl().clone();
533537

534538
// Get a reference to the outward-facing VNC server in this process.
535539
let vnc_server = server_context.services.vnc_server.clone();
536540

537541
// Initialize the Propolis VNC adapter with references to the VM's Instance,
538542
// framebuffer, and PS2 controller.
539-
vnc_server
540-
.server
541-
.initialize(vnc_fb, Arc::clone(ps2ctrl), vm.clone())
542-
.await;
543+
vnc_server.server.initialize(vnc_fb, ps2ctrl, vm.clone()).await;
543544

544545
// Hook up the framebuffer notifier to update the Propolis VNC adapter
545546
let notifier_server_ref = vnc_server.clone();

bin/propolis-server/src/lib/vcpu_tasks.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,13 @@ pub(crate) trait VcpuTaskController {
4747

4848
impl VcpuTasks {
4949
pub(crate) fn new(
50-
instance: propolis::instance::InstanceGuard,
50+
machine: &propolis::Machine,
5151
event_handler: Arc<super::vm::SharedVmState>,
5252
log: slog::Logger,
5353
) -> Result<Self, VcpuTaskError> {
5454
let generation = Arc::new(AtomicUsize::new(0));
5555
let mut tasks = Vec::new();
56-
for vcpu in instance.machine().vcpus.iter().map(Arc::clone) {
56+
for vcpu in machine.vcpus.iter().map(Arc::clone) {
5757
let (task, ctrl) =
5858
propolis::tasks::TaskHdl::new_held(Some(vcpu.barrier_fn()));
5959
let task_log = log.new(slog::o!("vcpu" => vcpu.id));

0 commit comments

Comments
 (0)