55// Use of this source code is governed by a BSD-style license that can be
66// found in the THIRD-PARTY file.
77
8+ use std:: convert:: Infallible ;
89use std:: fmt:: Debug ;
910use std:: sync:: { Arc , Mutex } ;
1011
@@ -13,7 +14,7 @@ use event_manager::{MutEventSubscriber, SubscriberOps};
1314#[ cfg( target_arch = "x86_64" ) ]
1415use legacy:: { LegacyDeviceError , PortIODeviceManager } ;
1516use linux_loader:: loader:: Cmdline ;
16- use log:: error;
17+ use log:: { error, info } ;
1718use mmio:: { MMIODeviceManager , MmioError } ;
1819use pci_mngr:: { PciDevices , PciDevicesConstructorArgs , PciManagerError } ;
1920use persist:: { ACPIDeviceManagerConstructorArgs , MMIODevManagerConstructorArgs } ;
@@ -30,8 +31,14 @@ use crate::devices::legacy::RTCDevice;
3031use crate :: devices:: legacy:: serial:: SerialOut ;
3132use crate :: devices:: legacy:: { IER_RDA_BIT , IER_RDA_OFFSET , SerialDevice } ;
3233use crate :: devices:: pseudo:: BootTimer ;
34+ use crate :: devices:: virtio:: balloon:: Balloon ;
35+ use crate :: devices:: virtio:: block:: device:: Block ;
3336use crate :: devices:: virtio:: device:: VirtioDevice ;
37+ use crate :: devices:: virtio:: net:: Net ;
38+ use crate :: devices:: virtio:: rng:: Entropy ;
3439use crate :: devices:: virtio:: transport:: mmio:: { IrqTrigger , MmioTransport } ;
40+ use crate :: devices:: virtio:: vsock:: { TYPE_VSOCK , Vsock , VsockUnixBackend } ;
41+ use crate :: devices:: virtio:: { TYPE_BALLOON , TYPE_BLOCK , TYPE_NET , TYPE_RNG } ;
3542use crate :: resources:: VmResources ;
3643use crate :: snapshot:: Persist ;
3744use crate :: vstate:: memory:: GuestMemoryMmap ;
@@ -274,6 +281,106 @@ impl DeviceManager {
274281 self . pci_devices
275282 . attach_pci_segment ( & self . resource_allocator )
276283 }
284+
285+ fn do_kick_device ( virtio_device : Arc < Mutex < dyn VirtioDevice > > ) {
286+ let mut device = virtio_device. lock ( ) . expect ( "Poisoned lock" ) ;
287+ match device. device_type ( ) {
288+ TYPE_BALLOON => {
289+ let balloon = device. as_mut_any ( ) . downcast_mut :: < Balloon > ( ) . unwrap ( ) ;
290+ // If device is activated, kick the balloon queue(s) to make up for any
291+ // pending or in-flight epoll events we may have not captured in snapshot.
292+ // Stats queue doesn't need kicking as it is notified via a `timer_fd`.
293+ if balloon. is_activated ( ) {
294+ info ! ( "kick balloon {}." , balloon. id( ) ) ;
295+ balloon. process_virtio_queues ( ) ;
296+ }
297+ }
298+ TYPE_BLOCK => {
299+ // We only care about kicking virtio block.
300+ // If we need to kick vhost-user-block we can do nothing.
301+ if let Some ( block) = device. as_mut_any ( ) . downcast_mut :: < Block > ( ) {
302+ // If device is activated, kick the block queue(s) to make up for any
303+ // pending or in-flight epoll events we may have not captured in
304+ // snapshot. No need to kick Ratelimiters
305+ // because they are restored 'unblocked' so
306+ // any inflight `timer_fd` events can be safely discarded.
307+ if block. is_activated ( ) {
308+ info ! ( "kick block {}." , block. id( ) ) ;
309+ block. process_virtio_queues ( ) ;
310+ }
311+ }
312+ }
313+ TYPE_NET => {
314+ let net = device. as_mut_any ( ) . downcast_mut :: < Net > ( ) . unwrap ( ) ;
315+ // If device is activated, kick the net queue(s) to make up for any
316+ // pending or in-flight epoll events we may have not captured in snapshot.
317+ // No need to kick Ratelimiters because they are restored 'unblocked' so
318+ // any inflight `timer_fd` events can be safely discarded.
319+ if net. is_activated ( ) {
320+ info ! ( "kick net {}." , net. id( ) ) ;
321+ net. process_virtio_queues ( ) ;
322+ }
323+ }
324+ TYPE_VSOCK => {
325+ // Vsock has complicated protocol that isn't resilient to any packet loss,
326+ // so for Vsock we don't support connection persistence through snapshot.
327+ // Any in-flight packets or events are simply lost.
328+ // Vsock is restored 'empty'.
329+ // The only reason we still `kick` it is to make guest process
330+ // `TRANSPORT_RESET_EVENT` event we sent during snapshot creation.
331+ let vsock = device
332+ . as_mut_any ( )
333+ . downcast_mut :: < Vsock < VsockUnixBackend > > ( )
334+ . unwrap ( ) ;
335+ if vsock. is_activated ( ) {
336+ info ! ( "kick vsock {}." , vsock. id( ) ) ;
337+ vsock. signal_used_queue ( 0 ) . unwrap ( ) ;
338+ }
339+ }
340+ TYPE_RNG => {
341+ let entropy = device. as_mut_any ( ) . downcast_mut :: < Entropy > ( ) . unwrap ( ) ;
342+ if entropy. is_activated ( ) {
343+ info ! ( "kick entropy {}." , entropy. id( ) ) ;
344+ entropy. process_virtio_queues ( ) ;
345+ }
346+ }
347+ _ => ( ) ,
348+ }
349+ }
350+
351+ /// Artificially kick VirtIO devices as if they had external events.
352+ pub fn kick_virtio_devices ( & self ) {
353+ info ! ( "Artificially kick devices" ) ;
354+ // Go through MMIO VirtIO devices
355+ let _: Result < ( ) , MmioError > = self . mmio_devices . for_each_virtio_device ( |_, _, device| {
356+ let mmio_transport_locked = device. inner . lock ( ) . expect ( "Poisoned lock" ) ;
357+ Self :: do_kick_device ( mmio_transport_locked. device ( ) ) ;
358+ Ok ( ( ) )
359+ } ) ;
360+ }
361+
362+ fn do_mark_virtio_queue_memory_dirty (
363+ device : Arc < Mutex < dyn VirtioDevice > > ,
364+ mem : & GuestMemoryMmap ,
365+ ) {
366+ // SAFETY:
367+ // This should never fail as we mark pages only if device has already been activated,
368+ // and the address validation was already performed on device activation.
369+ let locked_device = device. lock ( ) . expect ( "Poisoned lock" ) ;
370+ if locked_device. is_activated ( ) {
371+ locked_device. mark_queue_memory_dirty ( mem) . unwrap ( )
372+ }
373+ }
374+
375+ /// Mark queue memory dirty for activated VirtIO devices
376+ pub fn mark_virtio_queue_memory_dirty ( & self , mem : & GuestMemoryMmap ) {
377+ // Go through MMIO VirtIO devices
378+ let _: Result < ( ) , Infallible > = self . mmio_devices . for_each_virtio_device ( |_, _, device| {
379+ let mmio_transport_locked = device. inner . lock ( ) . expect ( "Poisoned locked" ) ;
380+ Self :: do_mark_virtio_queue_memory_dirty ( mmio_transport_locked. device ( ) , mem) ;
381+ Ok ( ( ) )
382+ } ) ;
383+ }
277384}
278385
279386#[ derive( Debug , Default , Clone , Serialize , Deserialize ) ]
0 commit comments