22// License, v. 2.0. If a copy of the MPL was not distributed with this
33// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44
5- //! A task to handle requests to change a VM's state or configuration.
5+ //! Structures and tasks that handle VM state and configuration change requests.
6+ //!
7+ //! This module handles the second high-level phase of a VM's lifecycle: once a
8+ //! VM's components and services exist, it enters an event loop that changes the
9+ //! VM's state in response to external API requests and signals arriving from
10+ //! within the VM. See the [`ensure`] module for more information about the
11+ //! initialization phase.
12+ //!
13+ //! This module's main struct is the [`StateDriver`], which holds references to
14+ //! an active VM's components, the VM's event queues, and the sender side of a
15+ //! channel that publishes instance state updates. External API requests are
16+ //! routed to the driver's event queue and handled by the driver task. This
17+ //! model ensures that only one task handles VM events and updates VM state; the
18+ //! idea is to minimize the number of different tasks and threads one has to
19+ //! consider when reasoning about concurrency in the VM state machine.
20+ //!
21+ //! On a migration in, the state driver implicitly starts the VM before entering
22+ //! the main event loop:
23+ //!
24+ //! ```text
25+ //! +-----------------------+
26+ //! | VM components created |
27+ //! +-----------+-----------+
28+ //! |
29+ //! |
30+ //! Yes +--------------v--------------+ No
31+ //! +-+ Initialized via migration? +-+
32+ //! | +-----------------------------+ |
33+ //! | |
34+ //! +------v--------+ |
35+ //! | Auto-start VM | |
36+ //! +------+--------+ |
37+ //! | |
38+ //! +------------v------------+ |
39+ //! | Start devices and vCPUs | |
40+ //! +------------+------------+ |
41+ //! | |
42+ //! | |
43+ //! | +-----------------------+ |
44+ //! +----> Enter main event loop <----+
45+ //! +-----------------------+
46+ //! ```
47+ //!
48+ //! Once in the main event loop, a VM generally remains active until it receives
49+ //! a signal telling it to do something else:
50+ //!
51+ //! ```text
52+ //! +-----------------+ +-----------------+ error during startup
53+ //! | Not yet started | | Not yet started | +--------+
54+ //! | (migrating in) | | (Creating) +-------> Failed |
55+ //! +-------+---------+ +--------+--------+ +--------+
56+ //! | |
57+ //! | | Successful start request
58+ //! +-----------+ |
59+ //! +v----------v-----------+ API/chipset request
60+ //! +---------+ Running +------+
61+ //! | +---^-------+--------^--+ +--v--------+
62+ //! | | | +------+ Rebooting |
63+ //! | | | +-----------+
64+ //! +--------v------+ | |
65+ //! | Migrating out +------+ | API/chipset request
66+ //! +--------+------+ |
67+ //! | +----v-----+
68+ //! | | Stopping |
69+ //! | +----+-----+
70+ //! | |
71+ //! | | +-----------------+
72+ //! | +----v-----+ | Destroyed |
73+ //! +----------------> Stopped +------> (after rundown) |
74+ //! +----------+ +-----------------+
75+ //! ```
76+ //!
77+ //! The state driver's [`InputQueue`] receives events that can push a running VM
78+ //! out of its steady "running" state. These can come either from the external
79+ //! API or from events happening in the guest (e.g. a vCPU asserting a pin on
80+ //! the virtual chipset that should reset or halt the VM). The policy that
81+ //! determines what API requests can be accepted in which states is implemented
82+ //! in the [`request_queue`] module.
83+ //!
84+ //! The "stopped" and "failed" states are terminal states. When the state driver
85+ //! reaches one of these states, it exits the event loop, returning its final
86+ //! state to the wrapper function that launched the driver. The wrapper task is
87+ //! responsible for running down the VM objects and structures and resetting the
88+ //! server so that it can start another VM.
89+ //!
90+ //! [`ensure`]: crate::vm::ensure
691
792use std:: {
893 sync:: { Arc , Mutex } ,
@@ -248,7 +333,10 @@ struct StateDriver {
248333 migration_src_state : crate :: migrate:: source:: PersistentState ,
249334}
250335
251- /// The values returned by a state driver task when it exits.
336+ /// Contains a state driver's terminal state and the channel it used to publish
337+ /// state updates to the rest of the server. The driver's owner can use these to
338+ /// publish the VM's terminal state after running down all of its objects and
339+ /// services.
252340pub ( super ) struct StateDriverOutput {
253341 /// The channel this driver used to publish external instance state changes.
254342 pub state_publisher : StatePublisher ,
@@ -258,9 +346,14 @@ pub(super) struct StateDriverOutput {
258346 pub final_state : InstanceState ,
259347}
260348
261- /// Creates a new set of VM objects in response to an `ensure_request` directed
262- /// to the supplied `vm`.
263- pub ( super ) async fn run_state_driver (
349+ /// Given an instance ensure request, processes the request and hands the
350+ /// resulting activated VM off to a [`StateDriver`] that will drive the main VM
351+ /// event loop.
352+ ///
353+ /// Returns the final state driver disposition. Note that this routine does not
354+ /// return a `Result`; if the VM fails to start, the returned
355+ /// [`StateDriverOutput`] contains appropriate state for a failed VM.
356+ pub ( super ) async fn ensure_vm_and_launch_driver (
264357 log : slog:: Logger ,
265358 vm : Arc < super :: Vm > ,
266359 mut state_publisher : StatePublisher ,
@@ -269,7 +362,7 @@ pub(super) async fn run_state_driver(
269362 ensure_options : super :: EnsureOptions ,
270363) -> StateDriverOutput {
271364 let ensure_options = Arc :: new ( ensure_options) ;
272- let activated_vm = match create_and_activate_vm (
365+ let activated_vm = match ensure_active_vm (
273366 & log,
274367 & vm,
275368 & mut state_publisher,
@@ -318,7 +411,7 @@ pub(super) async fn run_state_driver(
318411
319412/// Processes the supplied `ensure_request` to create a set of VM objects that
320413/// can be moved into a new `StateDriver`.
321- async fn create_and_activate_vm < ' a > (
414+ async fn ensure_active_vm < ' a > (
322415 log : & ' a slog:: Logger ,
323416 vm : & ' a Arc < super :: Vm > ,
324417 state_publisher : & ' a mut StatePublisher ,
@@ -371,23 +464,27 @@ async fn create_and_activate_vm<'a>(
371464}
372465
373466impl StateDriver {
467+ /// Directs this state driver to enter its main event loop. The driver may
468+ /// perform additional tasks (e.g. automatically starting a migration
469+ /// target) before it begins processing events from its queues.
374470 pub ( super ) async fn run ( mut self , migrated_in : bool ) -> StateDriverOutput {
375471 info ! ( self . log, "state driver launched" ) ;
376472
377473 let final_state = if migrated_in {
378474 if self . start_vm ( VmStartReason :: MigratedIn ) . await . is_ok ( ) {
379- self . run_loop ( ) . await
475+ self . event_loop ( ) . await
380476 } else {
381477 InstanceState :: Failed
382478 }
383479 } else {
384- self . run_loop ( ) . await
480+ self . event_loop ( ) . await
385481 } ;
386482
387483 StateDriverOutput { state_publisher : self . external_state , final_state }
388484 }
389485
390- async fn run_loop ( & mut self ) -> InstanceState {
486+ /// Runs the state driver's main event loop.
487+ async fn event_loop ( & mut self ) -> InstanceState {
391488 info ! ( self . log, "state driver entered main loop" ) ;
392489 loop {
393490 let event = self . input_queue . wait_for_next_event ( ) . await ;
@@ -415,6 +512,8 @@ impl StateDriver {
415512 }
416513 }
417514
515+ /// Starts the driver's VM by sending start commands to its devices and
516+ /// vCPUs.
418517 async fn start_vm (
419518 & mut self ,
420519 start_reason : VmStartReason ,
0 commit comments