Skip to content

Commit c6987de

Browse files
Manciukicroypat
authored andcommitted
refactor: reduce boilerplate to execute fn on virtio device
Make the with_virtio_device_with_id function more generic and introduce its variant with error handling try_with_virtio_device_with_id. Then use these new functions in vmm.rs whenever we need to perform an action on a device. To simplify the code, I also moved some balloon device error handling back to the balloon device code and refactored it a little bit. Signed-off-by: Riccardo Mancini <[email protected]>
1 parent ad58102 commit c6987de

File tree

4 files changed

+80
-113
lines changed

4 files changed

+80
-113
lines changed

src/vmm/src/device_manager/mod.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ pub enum FindDeviceError {
9191
/// Device not found
9292
DeviceNotFound,
9393
/// Internal Device error: {0}
94-
InternalDeviceError(String),
94+
InternalDeviceError(anyhow::Error),
9595
}
9696

9797
#[derive(Debug)]
@@ -371,27 +371,43 @@ impl DeviceManager {
371371
}
372372

373373
/// Run fn `f()` for the virtio device matching `virtio_type` and `id`.
374-
pub fn with_virtio_device_with_id<T, F>(
374+
pub fn try_with_virtio_device_with_id<T, F, R, E>(
375375
&self,
376376
virtio_type: u32,
377377
id: &str,
378378
f: F,
379-
) -> Result<(), FindDeviceError>
379+
) -> Result<R, FindDeviceError>
380380
where
381381
T: VirtioDevice + 'static + Debug,
382-
F: FnOnce(&mut T) -> Result<(), String>,
382+
E: std::error::Error + 'static + Send + Sync,
383+
F: FnOnce(&mut T) -> Result<R, E>,
383384
{
384385
if let Some(device) = self.get_virtio_device(virtio_type, id) {
385386
let mut dev = device.lock().expect("Poisoned lock");
386387
f(dev
387388
.as_mut_any()
388389
.downcast_mut::<T>()
389390
.ok_or(FindDeviceError::InvalidDeviceType)?)
390-
.map_err(FindDeviceError::InternalDeviceError)?;
391+
.map_err(|e| FindDeviceError::InternalDeviceError(e.into()))
391392
} else {
392-
return Err(FindDeviceError::DeviceNotFound);
393+
Err(FindDeviceError::DeviceNotFound)
393394
}
394-
Ok(())
395+
}
396+
397+
/// Run fn `f()` for the virtio device matching `virtio_type` and `id`.
398+
pub fn with_virtio_device_with_id<T, F, R>(
399+
&self,
400+
virtio_type: u32,
401+
id: &str,
402+
f: F,
403+
) -> Result<R, FindDeviceError>
404+
where
405+
T: VirtioDevice + 'static + Debug,
406+
F: FnOnce(&mut T) -> R,
407+
{
408+
self.try_with_virtio_device_with_id(virtio_type, id, |dev: &mut T| {
409+
Ok::<R, FindDeviceError>(f(dev))
410+
})
395411
}
396412
}
397413

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

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ use crate::devices::virtio::generated::virtio_ids::VIRTIO_ID_BALLOON;
3131
use crate::devices::virtio::queue::InvalidAvailIdx;
3232
use crate::devices::virtio::transport::{VirtioInterrupt, VirtioInterruptType};
3333
use crate::logger::IncMetric;
34+
use crate::mem_size_mib;
3435
use crate::utils::u64_to_usize;
3536
use crate::vstate::memory::{Address, ByteValued, Bytes, GuestAddress, GuestMemoryMmap};
3637

@@ -450,6 +451,12 @@ impl Balloon {
450451
/// Update the target size of the balloon.
451452
pub fn update_size(&mut self, amount_mib: u32) -> Result<(), BalloonError> {
452453
if self.is_activated() {
454+
let mem = &self.device_state.active_state().unwrap().mem;
455+
// The balloon cannot have a target size greater than the size of
456+
// the guest memory.
457+
if u64::from(amount_mib) > mem_size_mib(mem) {
458+
return Err(BalloonError::TooManyPagesRequested);
459+
}
453460
self.config_space.num_pages = mib_to_pages(amount_mib)?;
454461
self.interrupt_trigger()
455462
.trigger(VirtioInterruptType::Config)
@@ -504,15 +511,15 @@ impl Balloon {
504511
}
505512

506513
/// Retrieve latest stats for the balloon device.
507-
pub fn latest_stats(&mut self) -> Option<&BalloonStats> {
514+
pub fn latest_stats(&mut self) -> Result<&BalloonStats, BalloonError> {
508515
if self.stats_enabled() {
509516
self.latest_stats.target_pages = self.config_space.num_pages;
510517
self.latest_stats.actual_pages = self.config_space.actual_pages;
511518
self.latest_stats.target_mib = pages_to_mib(self.latest_stats.target_pages);
512519
self.latest_stats.actual_mib = pages_to_mib(self.latest_stats.actual_pages);
513-
Some(&self.latest_stats)
520+
Ok(&self.latest_stats)
514521
} else {
515-
None
522+
Err(BalloonError::StatisticsDisabled)
516523
}
517524
}
518525

@@ -1150,7 +1157,7 @@ pub(crate) mod tests {
11501157
let mut balloon = Balloon::new(0, true, 0, false).unwrap();
11511158
// Switch the state to active.
11521159
balloon.device_state = DeviceState::Activated(ActiveState {
1153-
mem: single_region_mem(0x1),
1160+
mem: single_region_mem(32 << 20),
11541161
interrupt: default_interrupt(),
11551162
});
11561163

src/vmm/src/lib.rs

Lines changed: 40 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,7 @@ use vstate::kvm::Kvm;
134134
use vstate::vcpu::{self, StartThreadedError, VcpuSendEventError};
135135

136136
use crate::cpu_config::templates::CpuConfiguration;
137-
use crate::devices::virtio::balloon::{
138-
BALLOON_DEV_ID, Balloon, BalloonConfig, BalloonError, BalloonStats,
139-
};
137+
use crate::devices::virtio::balloon::{BALLOON_DEV_ID, Balloon, BalloonConfig, BalloonStats};
140138
use crate::devices::virtio::block::device::Block;
141139
use crate::devices::virtio::generated::virtio_ids;
142140
use crate::devices::virtio::net::Net;
@@ -516,14 +514,10 @@ impl Vmm {
516514
path_on_host: String,
517515
) -> Result<(), VmmError> {
518516
self.device_manager
519-
.with_virtio_device_with_id(
517+
.try_with_virtio_device_with_id(
520518
virtio_ids::VIRTIO_ID_BLOCK,
521519
drive_id,
522-
|block: &mut Block| {
523-
block
524-
.update_disk_image(path_on_host)
525-
.map_err(|err| err.to_string())
526-
},
520+
|block: &mut Block| block.update_disk_image(path_on_host),
527521
)
528522
.map_err(VmmError::FindDeviceError)
529523
}
@@ -536,25 +530,21 @@ impl Vmm {
536530
rl_ops: BucketUpdate,
537531
) -> Result<(), VmmError> {
538532
self.device_manager
539-
.with_virtio_device_with_id(
533+
.try_with_virtio_device_with_id(
540534
virtio_ids::VIRTIO_ID_BLOCK,
541535
drive_id,
542-
|block: &mut Block| {
543-
block
544-
.update_rate_limiter(rl_bytes, rl_ops)
545-
.map_err(|err| err.to_string())
546-
},
536+
|block: &mut Block| block.update_rate_limiter(rl_bytes, rl_ops),
547537
)
548538
.map_err(VmmError::FindDeviceError)
549539
}
550540

551541
/// Updates the rate limiter parameters for block device with `drive_id` id.
552542
pub fn update_vhost_user_block_config(&mut self, drive_id: &str) -> Result<(), VmmError> {
553543
self.device_manager
554-
.with_virtio_device_with_id(
544+
.try_with_virtio_device_with_id(
555545
virtio_ids::VIRTIO_ID_BLOCK,
556546
drive_id,
557-
|block: &mut Block| block.update_config().map_err(|err| err.to_string()),
547+
|block: &mut Block| block.update_config(),
558548
)
559549
.map_err(VmmError::FindDeviceError)
560550
}
@@ -570,104 +560,56 @@ impl Vmm {
570560
) -> Result<(), VmmError> {
571561
self.device_manager
572562
.with_virtio_device_with_id(virtio_ids::VIRTIO_ID_NET, net_id, |net: &mut Net| {
573-
net.patch_rate_limiters(rx_bytes, rx_ops, tx_bytes, tx_ops);
574-
Ok(())
563+
net.patch_rate_limiters(rx_bytes, rx_ops, tx_bytes, tx_ops)
575564
})
576565
.map_err(VmmError::FindDeviceError)
577566
}
578567

579568
/// Returns a reference to the balloon device if present.
580-
pub fn balloon_config(&self) -> Result<BalloonConfig, BalloonError> {
581-
if let Some(virtio_device) = self
582-
.device_manager
583-
.get_virtio_device(virtio_ids::VIRTIO_ID_BALLOON, BALLOON_DEV_ID)
584-
{
585-
let config = virtio_device
586-
.lock()
587-
.expect("Poisoned lock")
588-
.as_mut_any()
589-
.downcast_mut::<Balloon>()
590-
.unwrap()
591-
.config();
592-
593-
Ok(config)
594-
} else {
595-
Err(BalloonError::DeviceNotFound)
596-
}
569+
pub fn balloon_config(&self) -> Result<BalloonConfig, VmmError> {
570+
self.device_manager
571+
.with_virtio_device_with_id(
572+
virtio_ids::VIRTIO_ID_BALLOON,
573+
BALLOON_DEV_ID,
574+
|dev: &mut Balloon| dev.config(),
575+
)
576+
.map_err(VmmError::FindDeviceError)
597577
}
598578

599579
/// Returns the latest balloon statistics if they are enabled.
600-
pub fn latest_balloon_stats(&self) -> Result<BalloonStats, BalloonError> {
601-
if let Some(virtio_device) = self
602-
.device_manager
603-
.get_virtio_device(virtio_ids::VIRTIO_ID_BALLOON, BALLOON_DEV_ID)
604-
{
605-
let latest_stats = virtio_device
606-
.lock()
607-
.expect("Poisoned lock")
608-
.as_mut_any()
609-
.downcast_mut::<Balloon>()
610-
.unwrap()
611-
.latest_stats()
612-
.ok_or(BalloonError::StatisticsDisabled)
613-
.cloned()?;
614-
615-
Ok(latest_stats)
616-
} else {
617-
Err(BalloonError::DeviceNotFound)
618-
}
580+
pub fn latest_balloon_stats(&self) -> Result<BalloonStats, VmmError> {
581+
self.device_manager
582+
.try_with_virtio_device_with_id(
583+
virtio_ids::VIRTIO_ID_BALLOON,
584+
BALLOON_DEV_ID,
585+
|dev: &mut Balloon| dev.latest_stats().cloned(),
586+
)
587+
.map_err(VmmError::FindDeviceError)
619588
}
620589

621590
/// Updates configuration for the balloon device target size.
622-
pub fn update_balloon_config(&mut self, amount_mib: u32) -> Result<(), BalloonError> {
623-
// The balloon cannot have a target size greater than the size of
624-
// the guest memory.
625-
if u64::from(amount_mib) > mem_size_mib(self.vm.guest_memory()) {
626-
return Err(BalloonError::TooManyPagesRequested);
627-
}
628-
629-
if let Some(virtio_device) = self
630-
.device_manager
631-
.get_virtio_device(virtio_ids::VIRTIO_ID_BALLOON, BALLOON_DEV_ID)
632-
{
633-
{
634-
virtio_device
635-
.lock()
636-
.expect("Poisoned lock")
637-
.as_mut_any()
638-
.downcast_mut::<Balloon>()
639-
.unwrap()
640-
.update_size(amount_mib)?;
641-
642-
Ok(())
643-
}
644-
} else {
645-
Err(BalloonError::DeviceNotFound)
646-
}
591+
pub fn update_balloon_config(&mut self, amount_mib: u32) -> Result<(), VmmError> {
592+
self.device_manager
593+
.try_with_virtio_device_with_id(
594+
virtio_ids::VIRTIO_ID_BALLOON,
595+
BALLOON_DEV_ID,
596+
|dev: &mut Balloon| dev.update_size(amount_mib),
597+
)
598+
.map_err(VmmError::FindDeviceError)
647599
}
648600

649601
/// Updates configuration for the balloon device as described in `balloon_stats_update`.
650602
pub fn update_balloon_stats_config(
651603
&mut self,
652604
stats_polling_interval_s: u16,
653-
) -> Result<(), BalloonError> {
654-
if let Some(virtio_device) = self
655-
.device_manager
656-
.get_virtio_device(virtio_ids::VIRTIO_ID_BALLOON, BALLOON_DEV_ID)
657-
{
658-
{
659-
virtio_device
660-
.lock()
661-
.expect("Poisoned lock")
662-
.as_mut_any()
663-
.downcast_mut::<Balloon>()
664-
.unwrap()
665-
.update_stats_polling_interval(stats_polling_interval_s)?;
666-
}
667-
Ok(())
668-
} else {
669-
Err(BalloonError::DeviceNotFound)
670-
}
605+
) -> Result<(), VmmError> {
606+
self.device_manager
607+
.try_with_virtio_device_with_id(
608+
virtio_ids::VIRTIO_ID_BALLOON,
609+
BALLOON_DEV_ID,
610+
|dev: &mut Balloon| dev.update_stats_polling_interval(stats_polling_interval_s),
611+
)
612+
.map_err(VmmError::FindDeviceError)
671613
}
672614

673615
/// Signals Vmm to stop and exit.

src/vmm/src/rpc_interface.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ pub enum VmmAction {
131131
pub enum VmmActionError {
132132
/// Balloon config error: {0}
133133
BalloonConfig(#[from] BalloonConfigError),
134+
/// Balloon update error: {0}
135+
BalloonUpdate(VmmError),
134136
/// Boot source error: {0}
135137
BootSource(#[from] BootSourceConfigError),
136138
/// Create snapshot error: {0}
@@ -637,14 +639,14 @@ impl RuntimeApiController {
637639
.expect("Poisoned lock")
638640
.balloon_config()
639641
.map(|state| VmmData::BalloonConfig(BalloonDeviceConfig::from(state)))
640-
.map_err(|err| VmmActionError::BalloonConfig(BalloonConfigError::from(err))),
642+
.map_err(VmmActionError::InternalVmm),
641643
GetBalloonStats => self
642644
.vmm
643645
.lock()
644646
.expect("Poisoned lock")
645647
.latest_balloon_stats()
646648
.map(VmmData::BalloonStats)
647-
.map_err(|err| VmmActionError::BalloonConfig(BalloonConfigError::from(err))),
649+
.map_err(VmmActionError::InternalVmm),
648650
GetFullVmConfig => Ok(VmmData::FullVmConfig((&self.vm_resources).into())),
649651
GetMMDS => self.get_mmds(),
650652
GetVmMachineConfig => Ok(VmmData::MachineConfiguration(
@@ -668,14 +670,14 @@ impl RuntimeApiController {
668670
.expect("Poisoned lock")
669671
.update_balloon_config(balloon_update.amount_mib)
670672
.map(|_| VmmData::Empty)
671-
.map_err(|err| VmmActionError::BalloonConfig(BalloonConfigError::from(err))),
673+
.map_err(VmmActionError::BalloonUpdate),
672674
UpdateBalloonStatistics(balloon_stats_update) => self
673675
.vmm
674676
.lock()
675677
.expect("Poisoned lock")
676678
.update_balloon_stats_config(balloon_stats_update.stats_polling_interval_s)
677679
.map(|_| VmmData::Empty)
678-
.map_err(|err| VmmActionError::BalloonConfig(BalloonConfigError::from(err))),
680+
.map_err(VmmActionError::BalloonUpdate),
679681
UpdateBlockDevice(new_cfg) => self.update_block_device(new_cfg),
680682
UpdateNetworkInterface(netif_update) => self.update_net_rate_limiters(netif_update),
681683

0 commit comments

Comments
 (0)