Skip to content

Commit 9ad721f

Browse files
committed
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 29c2b1a commit 9ad721f

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
@@ -89,7 +89,7 @@ pub enum FindDeviceError {
8989
/// Device not found
9090
DeviceNotFound,
9191
/// Internal Device error: {0}
92-
InternalDeviceError(String),
92+
InternalDeviceError(anyhow::Error),
9393
}
9494

9595
#[derive(Debug)]
@@ -355,27 +355,43 @@ impl DeviceManager {
355355
}
356356

357357
/// Run fn `f()` for the virtio device matching `virtio_type` and `id`.
358-
pub fn with_virtio_device_with_id<T, F>(
358+
pub fn try_with_virtio_device_with_id<T, F, R, E>(
359359
&self,
360360
virtio_type: u32,
361361
id: &str,
362362
f: F,
363-
) -> Result<(), FindDeviceError>
363+
) -> Result<R, FindDeviceError>
364364
where
365365
T: VirtioDevice + 'static + Debug,
366-
F: FnOnce(&mut T) -> Result<(), String>,
366+
E: std::error::Error + 'static + Send + Sync,
367+
F: FnOnce(&mut T) -> Result<R, E>,
367368
{
368369
if let Some(device) = self.get_virtio_device(virtio_type, id) {
369370
let mut dev = device.lock().expect("Poisoned lock");
370371
f(dev
371372
.as_mut_any()
372373
.downcast_mut::<T>()
373374
.ok_or(FindDeviceError::InvalidDeviceType)?)
374-
.map_err(FindDeviceError::InternalDeviceError)?;
375+
.map_err(|e| FindDeviceError::InternalDeviceError(e.into()))
375376
} else {
376-
return Err(FindDeviceError::DeviceNotFound);
377+
Err(FindDeviceError::DeviceNotFound)
377378
}
378-
Ok(())
379+
}
380+
381+
/// Run fn `f()` for the virtio device matching `virtio_type` and `id`.
382+
pub fn with_virtio_device_with_id<T, F, R>(
383+
&self,
384+
virtio_type: u32,
385+
id: &str,
386+
f: F,
387+
) -> Result<R, FindDeviceError>
388+
where
389+
T: VirtioDevice + 'static + Debug,
390+
F: FnOnce(&mut T) -> R,
391+
{
392+
self.try_with_virtio_device_with_id(virtio_type, id, |dev: &mut T| {
393+
Ok::<R, FindDeviceError>(f(dev))
394+
})
379395
}
380396
}
381397

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::mem::VirtioMemError;
@@ -525,14 +523,10 @@ impl Vmm {
525523
path_on_host: String,
526524
) -> Result<(), VmmError> {
527525
self.device_manager
528-
.with_virtio_device_with_id(
526+
.try_with_virtio_device_with_id(
529527
virtio_ids::VIRTIO_ID_BLOCK,
530528
drive_id,
531-
|block: &mut Block| {
532-
block
533-
.update_disk_image(path_on_host)
534-
.map_err(|err| err.to_string())
535-
},
529+
|block: &mut Block| block.update_disk_image(path_on_host),
536530
)
537531
.map_err(VmmError::FindDeviceError)
538532
}
@@ -545,25 +539,21 @@ impl Vmm {
545539
rl_ops: BucketUpdate,
546540
) -> Result<(), VmmError> {
547541
self.device_manager
548-
.with_virtio_device_with_id(
542+
.try_with_virtio_device_with_id(
549543
virtio_ids::VIRTIO_ID_BLOCK,
550544
drive_id,
551-
|block: &mut Block| {
552-
block
553-
.update_rate_limiter(rl_bytes, rl_ops)
554-
.map_err(|err| err.to_string())
555-
},
545+
|block: &mut Block| block.update_rate_limiter(rl_bytes, rl_ops),
556546
)
557547
.map_err(VmmError::FindDeviceError)
558548
}
559549

560550
/// Updates the rate limiter parameters for block device with `drive_id` id.
561551
pub fn update_vhost_user_block_config(&mut self, drive_id: &str) -> Result<(), VmmError> {
562552
self.device_manager
563-
.with_virtio_device_with_id(
553+
.try_with_virtio_device_with_id(
564554
virtio_ids::VIRTIO_ID_BLOCK,
565555
drive_id,
566-
|block: &mut Block| block.update_config().map_err(|err| err.to_string()),
556+
|block: &mut Block| block.update_config(),
567557
)
568558
.map_err(VmmError::FindDeviceError)
569559
}
@@ -579,104 +569,56 @@ impl Vmm {
579569
) -> Result<(), VmmError> {
580570
self.device_manager
581571
.with_virtio_device_with_id(virtio_ids::VIRTIO_ID_NET, net_id, |net: &mut Net| {
582-
net.patch_rate_limiters(rx_bytes, rx_ops, tx_bytes, tx_ops);
583-
Ok(())
572+
net.patch_rate_limiters(rx_bytes, rx_ops, tx_bytes, tx_ops)
584573
})
585574
.map_err(VmmError::FindDeviceError)
586575
}
587576

588577
/// Returns a reference to the balloon device if present.
589-
pub fn balloon_config(&self) -> Result<BalloonConfig, BalloonError> {
590-
if let Some(virtio_device) = self
591-
.device_manager
592-
.get_virtio_device(virtio_ids::VIRTIO_ID_BALLOON, BALLOON_DEV_ID)
593-
{
594-
let config = virtio_device
595-
.lock()
596-
.expect("Poisoned lock")
597-
.as_mut_any()
598-
.downcast_mut::<Balloon>()
599-
.unwrap()
600-
.config();
601-
602-
Ok(config)
603-
} else {
604-
Err(BalloonError::DeviceNotFound)
605-
}
578+
pub fn balloon_config(&self) -> Result<BalloonConfig, VmmError> {
579+
self.device_manager
580+
.with_virtio_device_with_id(
581+
virtio_ids::VIRTIO_ID_BALLOON,
582+
BALLOON_DEV_ID,
583+
|dev: &mut Balloon| dev.config(),
584+
)
585+
.map_err(VmmError::FindDeviceError)
606586
}
607587

608588
/// Returns the latest balloon statistics if they are enabled.
609-
pub fn latest_balloon_stats(&self) -> Result<BalloonStats, BalloonError> {
610-
if let Some(virtio_device) = self
611-
.device_manager
612-
.get_virtio_device(virtio_ids::VIRTIO_ID_BALLOON, BALLOON_DEV_ID)
613-
{
614-
let latest_stats = virtio_device
615-
.lock()
616-
.expect("Poisoned lock")
617-
.as_mut_any()
618-
.downcast_mut::<Balloon>()
619-
.unwrap()
620-
.latest_stats()
621-
.ok_or(BalloonError::StatisticsDisabled)
622-
.cloned()?;
623-
624-
Ok(latest_stats)
625-
} else {
626-
Err(BalloonError::DeviceNotFound)
627-
}
589+
pub fn latest_balloon_stats(&self) -> Result<BalloonStats, VmmError> {
590+
self.device_manager
591+
.try_with_virtio_device_with_id(
592+
virtio_ids::VIRTIO_ID_BALLOON,
593+
BALLOON_DEV_ID,
594+
|dev: &mut Balloon| dev.latest_stats().cloned(),
595+
)
596+
.map_err(VmmError::FindDeviceError)
628597
}
629598

630599
/// Updates configuration for the balloon device target size.
631-
pub fn update_balloon_config(&mut self, amount_mib: u32) -> Result<(), BalloonError> {
632-
// The balloon cannot have a target size greater than the size of
633-
// the guest memory.
634-
if u64::from(amount_mib) > mem_size_mib(self.vm.guest_memory()) {
635-
return Err(BalloonError::TooManyPagesRequested);
636-
}
637-
638-
if let Some(virtio_device) = self
639-
.device_manager
640-
.get_virtio_device(virtio_ids::VIRTIO_ID_BALLOON, BALLOON_DEV_ID)
641-
{
642-
{
643-
virtio_device
644-
.lock()
645-
.expect("Poisoned lock")
646-
.as_mut_any()
647-
.downcast_mut::<Balloon>()
648-
.unwrap()
649-
.update_size(amount_mib)?;
650-
651-
Ok(())
652-
}
653-
} else {
654-
Err(BalloonError::DeviceNotFound)
655-
}
600+
pub fn update_balloon_config(&mut self, amount_mib: u32) -> Result<(), VmmError> {
601+
self.device_manager
602+
.try_with_virtio_device_with_id(
603+
virtio_ids::VIRTIO_ID_BALLOON,
604+
BALLOON_DEV_ID,
605+
|dev: &mut Balloon| dev.update_size(amount_mib),
606+
)
607+
.map_err(VmmError::FindDeviceError)
656608
}
657609

658610
/// Updates configuration for the balloon device as described in `balloon_stats_update`.
659611
pub fn update_balloon_stats_config(
660612
&mut self,
661613
stats_polling_interval_s: u16,
662-
) -> Result<(), BalloonError> {
663-
if let Some(virtio_device) = self
664-
.device_manager
665-
.get_virtio_device(virtio_ids::VIRTIO_ID_BALLOON, BALLOON_DEV_ID)
666-
{
667-
{
668-
virtio_device
669-
.lock()
670-
.expect("Poisoned lock")
671-
.as_mut_any()
672-
.downcast_mut::<Balloon>()
673-
.unwrap()
674-
.update_stats_polling_interval(stats_polling_interval_s)?;
675-
}
676-
Ok(())
677-
} else {
678-
Err(BalloonError::DeviceNotFound)
679-
}
614+
) -> Result<(), VmmError> {
615+
self.device_manager
616+
.try_with_virtio_device_with_id(
617+
virtio_ids::VIRTIO_ID_BALLOON,
618+
BALLOON_DEV_ID,
619+
|dev: &mut Balloon| dev.update_stats_polling_interval(stats_polling_interval_s),
620+
)
621+
.map_err(VmmError::FindDeviceError)
680622
}
681623

682624
/// 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
@@ -132,6 +132,8 @@ pub enum VmmAction {
132132
pub enum VmmActionError {
133133
/// Balloon config error: {0}
134134
BalloonConfig(#[from] BalloonConfigError),
135+
/// Balloon update error: {0}
136+
BalloonUpdate(VmmError),
135137
/// Boot source error: {0}
136138
BootSource(#[from] BootSourceConfigError),
137139
/// Create snapshot error: {0}
@@ -647,14 +649,14 @@ impl RuntimeApiController {
647649
.expect("Poisoned lock")
648650
.balloon_config()
649651
.map(|state| VmmData::BalloonConfig(BalloonDeviceConfig::from(state)))
650-
.map_err(|err| VmmActionError::BalloonConfig(BalloonConfigError::from(err))),
652+
.map_err(VmmActionError::InternalVmm),
651653
GetBalloonStats => self
652654
.vmm
653655
.lock()
654656
.expect("Poisoned lock")
655657
.latest_balloon_stats()
656658
.map(VmmData::BalloonStats)
657-
.map_err(|err| VmmActionError::BalloonConfig(BalloonConfigError::from(err))),
659+
.map_err(VmmActionError::InternalVmm),
658660
GetFullVmConfig => Ok(VmmData::FullVmConfig((&self.vm_resources).into())),
659661
GetMMDS => self.get_mmds(),
660662
GetVmMachineConfig => Ok(VmmData::MachineConfiguration(
@@ -678,14 +680,14 @@ impl RuntimeApiController {
678680
.expect("Poisoned lock")
679681
.update_balloon_config(balloon_update.amount_mib)
680682
.map(|_| VmmData::Empty)
681-
.map_err(|err| VmmActionError::BalloonConfig(BalloonConfigError::from(err))),
683+
.map_err(VmmActionError::BalloonUpdate),
682684
UpdateBalloonStatistics(balloon_stats_update) => self
683685
.vmm
684686
.lock()
685687
.expect("Poisoned lock")
686688
.update_balloon_stats_config(balloon_stats_update.stats_polling_interval_s)
687689
.map(|_| VmmData::Empty)
688-
.map_err(|err| VmmActionError::BalloonConfig(BalloonConfigError::from(err))),
690+
.map_err(VmmActionError::BalloonUpdate),
689691
UpdateBlockDevice(new_cfg) => self.update_block_device(new_cfg),
690692
UpdateNetworkInterface(netif_update) => self.update_net_rate_limiters(netif_update),
691693

0 commit comments

Comments
 (0)