@@ -5,15 +5,14 @@ use std::collections::HashMap;
5
5
use std:: fmt:: Debug ;
6
6
use std:: sync:: { Arc , Mutex } ;
7
7
8
- use event_manager:: MutEventSubscriber ;
8
+ use event_manager:: { MutEventSubscriber , SubscriberOps } ;
9
9
use kvm_ioctls:: { IoEventAddress , NoDatamatch } ;
10
- use log:: { debug, error, warn} ;
10
+ use log:: { debug, error, info , warn} ;
11
11
use pci:: { PciBarRegionType , PciBdf , PciDevice , PciDeviceError , PciRootError } ;
12
12
use serde:: { Deserialize , Serialize } ;
13
13
use vm_device:: BusError ;
14
14
15
15
use super :: persist:: { MmdsVersionState , SharedDeviceType } ;
16
- use crate :: Vm ;
17
16
use crate :: devices:: pci:: PciSegment ;
18
17
use crate :: devices:: virtio:: balloon:: Balloon ;
19
18
use crate :: devices:: virtio:: balloon:: persist:: { BalloonConstructorArgs , BalloonState } ;
@@ -36,6 +35,7 @@ use crate::resources::VmResources;
36
35
use crate :: snapshot:: Persist ;
37
36
use crate :: vstate:: memory:: GuestMemoryMmap ;
38
37
use crate :: vstate:: vm:: { InterruptError , MsiVectorGroup } ;
38
+ use crate :: { EventManager , Vm } ;
39
39
40
40
#[ derive( Debug , Default ) ]
41
41
pub struct PciDevices {
@@ -180,7 +180,8 @@ impl PciDevices {
180
180
device : Arc < Mutex < T > > ,
181
181
device_id : & String ,
182
182
pci_device_bdf : PciBdf ,
183
- transport_state : & VirtioPciDeviceState ,
183
+ transport_state : VirtioPciDeviceState ,
184
+ event_manager : & mut EventManager ,
184
185
) -> Result < ( ) , PciManagerError > {
185
186
// We should only be reaching this point if PCI is enabled
186
187
let pci_segment = self . pci_segment . as_ref ( ) . unwrap ( ) ;
@@ -192,11 +193,11 @@ impl PciDevices {
192
193
let virtio_device = Arc :: new ( Mutex :: new ( VirtioPciDevice :: new_from_state (
193
194
device_id. to_string ( ) ,
194
195
vm. guest_memory ( ) . clone ( ) ,
195
- device,
196
+ device. clone ( ) ,
196
197
pci_device_bdf. into ( ) ,
197
198
msi_vector_group,
198
199
true ,
199
- transport_state. clone ( ) ,
200
+ transport_state,
200
201
) ?) ) ;
201
202
202
203
pci_segment
@@ -252,8 +253,87 @@ impl PciDevices {
252
253
vm. fd ( ) . register_ioevent ( queue_evt, & io_addr, NoDatamatch ) ?;
253
254
}
254
255
256
+ event_manager. add_subscriber ( device) ;
255
257
Ok ( ( ) )
256
258
}
259
+
260
+ /// Artificially kick devices as if they had external events.
261
+ pub fn kick_devices ( & self ) {
262
+ info ! ( "Artificially kick PCI devices." ) ;
263
+ // We only kick virtio devices for now.
264
+ for ( id, device) in & self . virtio_devices {
265
+ let virtio_device = device. lock ( ) . expect ( "Poisoned lock" ) . virtio_device ( ) ;
266
+ let mut virtio_locked = virtio_device. lock ( ) . expect ( "Poisoned lock" ) ;
267
+ match virtio_locked. device_type ( ) {
268
+ TYPE_BALLOON => {
269
+ let balloon = virtio_locked
270
+ . as_mut_any ( )
271
+ . downcast_mut :: < Balloon > ( )
272
+ . unwrap ( ) ;
273
+ // If device is activated, kick the balloon queue(s) to make up for any
274
+ // pending or in-flight epoll events we may have not captured in snapshot.
275
+ // Stats queue doesn't need kicking as it is notified via a `timer_fd`.
276
+ if balloon. is_activated ( ) {
277
+ info ! ( "kick balloon {}." , id) ;
278
+ balloon. process_virtio_queues ( ) ;
279
+ }
280
+ }
281
+ TYPE_BLOCK => {
282
+ // We only care about kicking virtio block.
283
+ // If we need to kick vhost-user-block we can do nothing.
284
+ if let Some ( block) = virtio_locked. as_mut_any ( ) . downcast_mut :: < Block > ( ) {
285
+ // If device is activated, kick the block queue(s) to make up for any
286
+ // pending or in-flight epoll events we may have not captured in
287
+ // snapshot. No need to kick Ratelimiters
288
+ // because they are restored 'unblocked' so
289
+ // any inflight `timer_fd` events can be safely discarded.
290
+ if block. is_activated ( ) {
291
+ info ! ( "kick block {}." , id) ;
292
+ block. process_virtio_queues ( ) ;
293
+ }
294
+ }
295
+ }
296
+ TYPE_NET => {
297
+ let net = virtio_locked. as_mut_any ( ) . downcast_mut :: < Net > ( ) . unwrap ( ) ;
298
+ // If device is activated, kick the net queue(s) to make up for any
299
+ // pending or in-flight epoll events we may have not captured in snapshot.
300
+ // No need to kick Ratelimiters because they are restored 'unblocked' so
301
+ // any inflight `timer_fd` events can be safely discarded.
302
+ if net. is_activated ( ) {
303
+ info ! ( "kick net {}." , id) ;
304
+ net. process_virtio_queues ( ) ;
305
+ }
306
+ }
307
+ TYPE_VSOCK => {
308
+ // Vsock has complicated protocol that isn't resilient to any packet loss,
309
+ // so for Vsock we don't support connection persistence through snapshot.
310
+ // Any in-flight packets or events are simply lost.
311
+ // Vsock is restored 'empty'.
312
+ // The only reason we still `kick` it is to make guest process
313
+ // `TRANSPORT_RESET_EVENT` event we sent during snapshot creation.
314
+ let vsock = virtio_locked
315
+ . as_mut_any ( )
316
+ . downcast_mut :: < Vsock < VsockUnixBackend > > ( )
317
+ . unwrap ( ) ;
318
+ if vsock. is_activated ( ) {
319
+ info ! ( "kick vsock {id}." ) ;
320
+ vsock. signal_used_queue ( 0 ) . unwrap ( ) ;
321
+ }
322
+ }
323
+ TYPE_RNG => {
324
+ let entropy = virtio_locked
325
+ . as_mut_any ( )
326
+ . downcast_mut :: < Entropy > ( )
327
+ . unwrap ( ) ;
328
+ if entropy. is_activated ( ) {
329
+ info ! ( "kick entropy {id}." ) ;
330
+ entropy. process_virtio_queues ( ) ;
331
+ }
332
+ }
333
+ _ => ( ) ,
334
+ }
335
+ }
336
+ }
257
337
}
258
338
259
339
#[ derive( Debug , Clone , Serialize , Deserialize ) ]
@@ -286,13 +366,25 @@ pub struct PciDevicesState {
286
366
pub entropy_device : Option < VirtioDeviceState < EntropyState > > ,
287
367
}
288
368
289
- #[ derive( Debug ) ]
290
369
pub struct PciDevicesConstructorArgs < ' a > {
291
370
pub vm : Arc < Vm > ,
292
371
pub mem : & ' a GuestMemoryMmap ,
293
372
pub vm_resources : & ' a mut VmResources ,
294
373
pub instance_id : & ' a str ,
295
374
pub restored_from_file : bool ,
375
+ pub event_manager : & ' a mut EventManager ,
376
+ }
377
+
378
+ impl < ' a > Debug for PciDevicesConstructorArgs < ' a > {
379
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
380
+ f. debug_struct ( "PciDevicesConstructorArgs" )
381
+ . field ( "vm" , & self . vm )
382
+ . field ( "mem" , & self . mem )
383
+ . field ( "vm_resources" , & self . vm_resources )
384
+ . field ( "instance_id" , & self . instance_id )
385
+ . field ( "restored_from_file" , & self . restored_from_file )
386
+ . finish ( )
387
+ }
296
388
}
297
389
298
390
impl < ' a > Persist < ' a > for PciDevices {
@@ -461,7 +553,8 @@ impl<'a> Persist<'a> for PciDevices {
461
553
device,
462
554
& balloon_state. device_id ,
463
555
balloon_state. pci_device_bdf . into ( ) ,
464
- & balloon_state. transport_state ,
556
+ balloon_state. transport_state . clone ( ) ,
557
+ constructor_args. event_manager ,
465
558
)
466
559
. unwrap ( )
467
560
}
@@ -486,7 +579,8 @@ impl<'a> Persist<'a> for PciDevices {
486
579
device,
487
580
& block_state. device_id ,
488
581
block_state. pci_device_bdf . into ( ) ,
489
- & block_state. transport_state ,
582
+ block_state. transport_state . clone ( ) ,
583
+ constructor_args. event_manager ,
490
584
)
491
585
. unwrap ( )
492
586
}
@@ -536,7 +630,8 @@ impl<'a> Persist<'a> for PciDevices {
536
630
device,
537
631
& net_state. device_id ,
538
632
net_state. pci_device_bdf . into ( ) ,
539
- & net_state. transport_state ,
633
+ net_state. transport_state . clone ( ) ,
634
+ constructor_args. event_manager ,
540
635
)
541
636
. unwrap ( )
542
637
}
@@ -569,7 +664,8 @@ impl<'a> Persist<'a> for PciDevices {
569
664
device,
570
665
& vsock_state. device_id ,
571
666
vsock_state. pci_device_bdf . into ( ) ,
572
- & vsock_state. transport_state ,
667
+ vsock_state. transport_state . clone ( ) ,
668
+ constructor_args. event_manager ,
573
669
)
574
670
. unwrap ( )
575
671
}
@@ -592,7 +688,8 @@ impl<'a> Persist<'a> for PciDevices {
592
688
device,
593
689
& entropy_state. device_id ,
594
690
entropy_state. pci_device_bdf . into ( ) ,
595
- & entropy_state. transport_state ,
691
+ entropy_state. transport_state . clone ( ) ,
692
+ constructor_args. event_manager ,
596
693
)
597
694
. unwrap ( )
598
695
}
0 commit comments