Skip to content

Commit b1e12b7

Browse files
committed
feat(virtio/mmio): MmioTransport knows about vhost_user
Now `MmioTransport` stores info if the device uses vhost_user implementation. Based on this info the interrupt status reported to the guest is either an updatde interrupt status (for usual virtio devices) or `VIRTIO_MMIO_INT_VRING`(0x1) for vhost_user devices. This is done because vhost_user devices can not update interrupt status variable in the FC. Signed-off-by: Egor Lazarchuk <[email protected]>
1 parent 4ceea3a commit b1e12b7

File tree

5 files changed

+78
-22
lines changed

5 files changed

+78
-22
lines changed

src/vmm/src/builder.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -835,13 +835,14 @@ fn attach_virtio_device<T: 'static + VirtioDevice + MutEventSubscriber + Debug>(
835835
id: String,
836836
device: Arc<Mutex<T>>,
837837
cmdline: &mut LoaderKernelCmdline,
838+
is_vhost_user: bool,
838839
) -> Result<(), StartMicrovmError> {
839840
use self::StartMicrovmError::*;
840841

841842
event_manager.add_subscriber(device.clone());
842843

843844
// The device mutex mustn't be locked here otherwise it will deadlock.
844-
let device = MmioTransport::new(vmm.guest_memory().clone(), device);
845+
let device = MmioTransport::new(vmm.guest_memory().clone(), device, is_vhost_user);
845846
vmm.mmio_device_manager
846847
.register_mmio_virtio_for_boot(vmm.vm.fd(), id, device, cmdline)
847848
.map_err(RegisterMmioDevice)
@@ -875,7 +876,14 @@ fn attach_entropy_device(
875876
.id()
876877
.to_string();
877878

878-
attach_virtio_device(event_manager, vmm, id, entropy_device.clone(), cmdline)
879+
attach_virtio_device(
880+
event_manager,
881+
vmm,
882+
id,
883+
entropy_device.clone(),
884+
cmdline,
885+
false,
886+
)
879887
}
880888

881889
fn attach_block_devices<'a, I: Iterator<Item = &'a BlockDeviceType> + Debug>(
@@ -885,7 +893,7 @@ fn attach_block_devices<'a, I: Iterator<Item = &'a BlockDeviceType> + Debug>(
885893
event_manager: &mut EventManager,
886894
) -> Result<(), StartMicrovmError> {
887895
macro_rules! attach_block {
888-
($block:ident) => {
896+
($block:ident, $is_vhost_user:ident) => {
889897
let id = {
890898
let locked = $block.lock().expect("Poisoned lock");
891899
if locked.root_device {
@@ -903,17 +911,24 @@ fn attach_block_devices<'a, I: Iterator<Item = &'a BlockDeviceType> + Debug>(
903911
locked.id.clone()
904912
};
905913
// The device mutex mustn't be locked here otherwise it will deadlock.
906-
attach_virtio_device(event_manager, vmm, id, $block.clone(), cmdline)?;
914+
attach_virtio_device(
915+
event_manager,
916+
vmm,
917+
id,
918+
$block.clone(),
919+
cmdline,
920+
$is_vhost_user,
921+
)?;
907922
};
908923
}
909924

910925
for block in blocks {
911926
match block {
912927
BlockDeviceType::VirtioBlock(block) => {
913-
attach_block!(block);
928+
attach_block!(block, false);
914929
}
915930
BlockDeviceType::VhostUserBlock(block) => {
916-
attach_block!(block);
931+
attach_block!(block, true);
917932
}
918933
};
919934
}
@@ -929,7 +944,7 @@ fn attach_net_devices<'a, I: Iterator<Item = &'a Arc<Mutex<Net>>> + Debug>(
929944
for net_device in net_devices {
930945
let id = net_device.lock().expect("Poisoned lock").id().clone();
931946
// The device mutex mustn't be locked here otherwise it will deadlock.
932-
attach_virtio_device(event_manager, vmm, id, net_device.clone(), cmdline)?;
947+
attach_virtio_device(event_manager, vmm, id, net_device.clone(), cmdline, false)?;
933948
}
934949
Ok(())
935950
}
@@ -942,7 +957,7 @@ fn attach_unixsock_vsock_device(
942957
) -> Result<(), StartMicrovmError> {
943958
let id = String::from(unix_vsock.lock().expect("Poisoned lock").id());
944959
// The device mutex mustn't be locked here otherwise it will deadlock.
945-
attach_virtio_device(event_manager, vmm, id, unix_vsock.clone(), cmdline)
960+
attach_virtio_device(event_manager, vmm, id, unix_vsock.clone(), cmdline, false)
946961
}
947962

948963
fn attach_balloon_device(
@@ -953,7 +968,7 @@ fn attach_balloon_device(
953968
) -> Result<(), StartMicrovmError> {
954969
let id = String::from(balloon.lock().expect("Poisoned lock").id());
955970
// The device mutex mustn't be locked here otherwise it will deadlock.
956-
attach_virtio_device(event_manager, vmm, id, balloon.clone(), cmdline)
971+
attach_virtio_device(event_manager, vmm, id, balloon.clone(), cmdline, false)
957972
}
958973

959974
// Adds `O_NONBLOCK` to the stdout flags.

src/vmm/src/device_manager/mmio.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ mod tests {
483483
cmdline: &mut kernel_cmdline::Cmdline,
484484
dev_id: &str,
485485
) -> Result<u64, MmioError> {
486-
let mmio_device = MmioTransport::new(guest_mem, device);
486+
let mmio_device = MmioTransport::new(guest_mem, device, false);
487487
let device_info =
488488
self.register_mmio_virtio_for_boot(vm, dev_id.to_string(), mmio_device, cmdline)?;
489489
Ok(device_info.addr)

src/vmm/src/device_manager/persist.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,7 @@ impl<'a> Persist<'a> for MMIODeviceManager {
446446
}
447447

448448
let mut restore_helper = |device: Arc<Mutex<dyn VirtioDevice>>,
449+
is_vhost_user: bool,
449450
as_subscriber: Arc<Mutex<dyn MutEventSubscriber>>,
450451
id: &String,
451452
state: &MmioTransportState,
@@ -455,6 +456,7 @@ impl<'a> Persist<'a> for MMIODeviceManager {
455456
let restore_args = MmioTransportConstructorArgs {
456457
mem: mem.clone(),
457458
device,
459+
is_vhost_user,
458460
};
459461
let mmio_transport = MmioTransport::restore(restore_args, state)
460462
.map_err(|()| DevicePersistError::MmioTransport)?;
@@ -499,6 +501,7 @@ impl<'a> Persist<'a> for MMIODeviceManager {
499501

500502
restore_helper(
501503
device.clone(),
504+
false,
502505
device,
503506
&balloon_state.device_id,
504507
&balloon_state.transport_state,
@@ -520,6 +523,7 @@ impl<'a> Persist<'a> for MMIODeviceManager {
520523

521524
restore_helper(
522525
device.clone(),
526+
false,
523527
device,
524528
&virtio_block_state.device_id,
525529
&virtio_block_state.transport_state,
@@ -541,6 +545,7 @@ impl<'a> Persist<'a> for MMIODeviceManager {
541545

542546
restore_helper(
543547
device.clone(),
548+
true,
544549
device,
545550
&vhost_user_block_state.device_id,
546551
&vhost_user_block_state.transport_state,
@@ -586,6 +591,7 @@ impl<'a> Persist<'a> for MMIODeviceManager {
586591

587592
restore_helper(
588593
device.clone(),
594+
false,
589595
device,
590596
&net_state.device_id,
591597
&net_state.transport_state,
@@ -614,6 +620,7 @@ impl<'a> Persist<'a> for MMIODeviceManager {
614620

615621
restore_helper(
616622
device.clone(),
623+
false,
617624
device,
618625
&vsock_state.device_id,
619626
&vsock_state.transport_state,
@@ -637,6 +644,7 @@ impl<'a> Persist<'a> for MMIODeviceManager {
637644

638645
restore_helper(
639646
device.clone(),
647+
false,
640648
device,
641649
&entropy_state.device_id,
642650
&entropy_state.transport_state,

src/vmm/src/devices/virtio/mmio.rs

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,16 @@ pub struct MmioTransport {
5757
pub(crate) config_generation: u32,
5858
mem: GuestMemoryMmap,
5959
pub(crate) interrupt_status: Arc<AtomicU32>,
60+
pub is_vhost_user: bool,
6061
}
6162

6263
impl MmioTransport {
6364
/// Constructs a new MMIO transport for the given virtio device.
64-
pub fn new(mem: GuestMemoryMmap, device: Arc<Mutex<dyn VirtioDevice>>) -> MmioTransport {
65+
pub fn new(
66+
mem: GuestMemoryMmap,
67+
device: Arc<Mutex<dyn VirtioDevice>>,
68+
is_vhost_user: bool,
69+
) -> MmioTransport {
6570
let interrupt_status = device.lock().expect("Poisoned lock").interrupt_status();
6671

6772
MmioTransport {
@@ -73,6 +78,7 @@ impl MmioTransport {
7378
config_generation: 0,
7479
mem,
7580
interrupt_status,
81+
is_vhost_user,
7682
}
7783
}
7884

@@ -239,7 +245,19 @@ impl MmioTransport {
239245
}
240246
0x34 => self.with_queue(0, |q| u32::from(q.get_max_size())),
241247
0x44 => self.with_queue(0, |q| u32::from(q.ready)),
242-
0x60 => self.interrupt_status.load(Ordering::SeqCst),
248+
0x60 => {
249+
// For vhost-user backed devices we can only report
250+
// `VIRTIO_MMIO_INT_VRING` (bit 0 set) value, as any
251+
// changes to the interrupt status value cannot be propagated
252+
// back to FC from vhost-user-backend. This also means that backed should
253+
// not change device configuration as it also requires update to the
254+
// interrupt status (bit 1 set).
255+
if !self.is_vhost_user {
256+
self.interrupt_status.load(Ordering::SeqCst)
257+
} else {
258+
VIRTIO_MMIO_INT_VRING
259+
}
260+
}
243261
0x70 => self.device_status,
244262
0xfc => self.config_generation,
245263
_ => {
@@ -440,7 +458,7 @@ pub(crate) mod tests {
440458
let mut dummy = DummyDevice::new();
441459
// Validate reset is no-op.
442460
assert!(dummy.reset().is_none());
443-
let mut d = MmioTransport::new(m, Arc::new(Mutex::new(dummy)));
461+
let mut d = MmioTransport::new(m, Arc::new(Mutex::new(dummy)), false);
444462

445463
// We just make sure here that the implementation of a mmio device behaves as we expect,
446464
// given a known virtio device implementation (the dummy device).
@@ -469,7 +487,7 @@ pub(crate) mod tests {
469487
#[test]
470488
fn test_bus_device_read() {
471489
let m = GuestMemoryMmap::from_raw_regions(&[(GuestAddress(0), 0x1000)], false).unwrap();
472-
let mut d = MmioTransport::new(m, Arc::new(Mutex::new(DummyDevice::new())));
490+
let mut d = MmioTransport::new(m, Arc::new(Mutex::new(DummyDevice::new())), false);
473491

474492
let mut buf = vec![0xff, 0, 0xfe, 0];
475493
let buf_copy = buf.to_vec();
@@ -520,6 +538,11 @@ pub(crate) mod tests {
520538
d.bus_read(0x60, &mut buf[..]);
521539
assert_eq!(read_le_u32(&buf[..]), 111);
522540

541+
d.is_vhost_user = true;
542+
d.interrupt_status.store(222, Ordering::SeqCst);
543+
d.bus_read(0x60, &mut buf[..]);
544+
assert_eq!(read_le_u32(&buf[..]), VIRTIO_MMIO_INT_VRING);
545+
523546
d.bus_read(0x70, &mut buf[..]);
524547
assert_eq!(read_le_u32(&buf[..]), 0);
525548

@@ -548,7 +571,7 @@ pub(crate) mod tests {
548571
fn test_bus_device_write() {
549572
let m = GuestMemoryMmap::from_raw_regions(&[(GuestAddress(0), 0x1000)], false).unwrap();
550573
let dummy_dev = Arc::new(Mutex::new(DummyDevice::new()));
551-
let mut d = MmioTransport::new(m, dummy_dev.clone());
574+
let mut d = MmioTransport::new(m, dummy_dev.clone(), false);
552575
let mut buf = vec![0; 5];
553576
write_le_u32(&mut buf[..4], 1);
554577

@@ -706,7 +729,7 @@ pub(crate) mod tests {
706729
#[test]
707730
fn test_bus_device_activate() {
708731
let m = GuestMemoryMmap::from_raw_regions(&[(GuestAddress(0), 0x1000)], false).unwrap();
709-
let mut d = MmioTransport::new(m, Arc::new(Mutex::new(DummyDevice::new())));
732+
let mut d = MmioTransport::new(m, Arc::new(Mutex::new(DummyDevice::new())), false);
710733

711734
assert!(!d.are_queues_valid());
712735
assert!(!d.locked_device().is_activated());
@@ -824,7 +847,7 @@ pub(crate) mod tests {
824847
#[test]
825848
fn test_bus_device_reset() {
826849
let m = GuestMemoryMmap::from_raw_regions(&[(GuestAddress(0), 0x1000)], false).unwrap();
827-
let mut d = MmioTransport::new(m, Arc::new(Mutex::new(DummyDevice::new())));
850+
let mut d = MmioTransport::new(m, Arc::new(Mutex::new(DummyDevice::new())), false);
828851
let mut buf = [0; 4];
829852

830853
assert!(!d.are_queues_valid());

src/vmm/src/devices/virtio/persist.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ pub struct MmioTransportConstructorArgs {
205205
pub mem: GuestMemoryMmap,
206206
/// Device associated with the current MMIO state.
207207
pub device: Arc<Mutex<dyn VirtioDevice>>,
208+
/// Is device backed by vhost-user.
209+
pub is_vhost_user: bool,
208210
}
209211

210212
impl Persist<'_> for MmioTransport {
@@ -226,7 +228,11 @@ impl Persist<'_> for MmioTransport {
226228
constructor_args: Self::ConstructorArgs,
227229
state: &Self::State,
228230
) -> Result<Self, Self::Error> {
229-
let mut transport = MmioTransport::new(constructor_args.mem, constructor_args.device);
231+
let mut transport = MmioTransport::new(
232+
constructor_args.mem,
233+
constructor_args.device,
234+
constructor_args.is_vhost_user,
235+
);
230236
transport.features_select = state.features_select;
231237
transport.acked_features_select = state.acked_features_select;
232238
transport.queue_select = state.queue_select;
@@ -391,7 +397,11 @@ mod tests {
391397
.serialize(&mut buf.as_mut_slice(), &version_map, 1)
392398
.unwrap();
393399

394-
let restore_args = MmioTransportConstructorArgs { mem, device };
400+
let restore_args = MmioTransportConstructorArgs {
401+
mem,
402+
device,
403+
is_vhost_user: false,
404+
};
395405
let restored_mmio_transport = MmioTransport::restore(
396406
restore_args,
397407
&MmioTransportState::deserialize(&mut buf.as_slice(), &version_map, 1).unwrap(),
@@ -412,15 +422,15 @@ mod tests {
412422
FileEngineType::default(),
413423
);
414424
let block = Arc::new(Mutex::new(block));
415-
let mmio_transport = MmioTransport::new(mem.clone(), block.clone());
425+
let mmio_transport = MmioTransport::new(mem.clone(), block.clone(), false);
416426

417427
(mmio_transport, mem, block)
418428
}
419429

420430
fn create_default_net() -> (MmioTransport, GuestMemoryMmap, Arc<Mutex<Net>>) {
421431
let mem = default_mem();
422432
let net = Arc::new(Mutex::new(default_net()));
423-
let mmio_transport = MmioTransport::new(mem.clone(), net.clone());
433+
let mmio_transport = MmioTransport::new(mem.clone(), net.clone(), false);
424434

425435
(mmio_transport, mem, net)
426436
}
@@ -440,7 +450,7 @@ mod tests {
440450
let backend = VsockUnixBackend::new(guest_cid, uds_path).unwrap();
441451
let vsock = Vsock::new(guest_cid, backend).unwrap();
442452
let vsock = Arc::new(Mutex::new(vsock));
443-
let mmio_transport = MmioTransport::new(mem.clone(), vsock.clone());
453+
let mmio_transport = MmioTransport::new(mem.clone(), vsock.clone(), false);
444454

445455
(mmio_transport, mem, vsock)
446456
}

0 commit comments

Comments
 (0)