5
5
// Use of this source code is governed by a BSD-style license that can be
6
6
// found in the THIRD-PARTY file.
7
7
8
+ use std:: convert:: Infallible ;
8
9
use std:: fmt:: Debug ;
9
10
use std:: sync:: { Arc , Mutex } ;
10
11
@@ -13,7 +14,7 @@ use event_manager::{MutEventSubscriber, SubscriberOps};
13
14
#[ cfg( target_arch = "x86_64" ) ]
14
15
use legacy:: { LegacyDeviceError , PortIODeviceManager } ;
15
16
use linux_loader:: loader:: Cmdline ;
16
- use log:: error;
17
+ use log:: { error, info } ;
17
18
use mmio:: { MMIODeviceManager , MmioError } ;
18
19
use pci_mngr:: { PciDevices , PciDevicesConstructorArgs , PciManagerError } ;
19
20
use persist:: { ACPIDeviceManagerConstructorArgs , MMIODevManagerConstructorArgs } ;
@@ -30,8 +31,14 @@ use crate::devices::legacy::RTCDevice;
30
31
use crate :: devices:: legacy:: serial:: SerialOut ;
31
32
use crate :: devices:: legacy:: { IER_RDA_BIT , IER_RDA_OFFSET , SerialDevice } ;
32
33
use crate :: devices:: pseudo:: BootTimer ;
34
+ use crate :: devices:: virtio:: balloon:: Balloon ;
35
+ use crate :: devices:: virtio:: block:: device:: Block ;
33
36
use crate :: devices:: virtio:: device:: VirtioDevice ;
37
+ use crate :: devices:: virtio:: net:: Net ;
38
+ use crate :: devices:: virtio:: rng:: Entropy ;
34
39
use 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 } ;
35
42
use crate :: resources:: VmResources ;
36
43
use crate :: snapshot:: Persist ;
37
44
use crate :: vstate:: memory:: GuestMemoryMmap ;
@@ -274,6 +281,106 @@ impl DeviceManager {
274
281
self . pci_devices
275
282
. attach_pci_segment ( & self . resource_allocator )
276
283
}
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
+ }
277
384
}
278
385
279
386
#[ derive( Debug , Default , Clone , Serialize , Deserialize ) ]
0 commit comments