1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! crate for the vmm-swap feature.

#![deny(missing_docs)]

cfg_if::cfg_if! {
    if #[cfg(all(unix, feature = "enable"))] {
        mod controller;
        mod file;
        mod file_truncator;
        mod pagesize;
        mod present_list;
        // this is public only for integration tests.
        pub mod page_handler;
        mod processes;
        mod staging;
        mod uffd_list;
        // this is public only for integration tests.
        pub mod userfaultfd;
        // this is public only for integration tests.
        pub mod worker;

        pub use crate::controller::SwapDeviceHelper;
        pub use crate::controller::PrepareFork;
        pub use crate::controller::SwapController;
        pub use crate::controller::SwapDeviceUffdSender;
    }
}

use serde::Deserialize;
use serde::Serialize;

/// Current state of vmm-swap.
///
/// This should not contain fields but be a plain enum because this will be displayed to user using
/// `serde_json` crate.
#[repr(C)]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
pub enum SwapState {
    /// vmm-swap is ready. userfaultfd is disabled until vmm-swap is enabled.
    Ready = 0,
    /// swap out failed.
    Failed = 1,
    /// Pages in guest memory are moved to the staging memory.
    Pending = 2,
    /// Trimming staging memory.
    TrimInProgress = 3,
    /// swap-out is in progress.
    SwapOutInProgress = 4,
    /// swap out succeeded.
    Active = 5,
    /// swap-in is in progress.
    SwapInInProgress = 6,
}

/// Latency and number of pages of swap operations (move to staging, swap out, swap in).
///
/// The meaning of `StateTransition` depends on `State`.
///
/// | `State`             | `StateTransition`                            |
/// |---------------------|----------------------------------------------|
/// | `Ready`             | empty or transition record of `swap disable` |
/// | `Pending`           | transition record of `swap enable`           |
/// | `SwapOutInProgress` | transition record of `swap out`              |
/// | `Active`            | transition record of `swap out`              |
/// | `SwapInInProgress`  | transition record of `swap disable`          |
/// | `Failed`            | empty                                        |
#[repr(C)]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)]
pub struct SwapStateTransition {
    /// The number of pages moved for the state transition.
    pub pages: u64,
    /// Time taken for the state transition.
    pub time_ms: u64,
}

/// Current metrics of vmm-swap.
///
/// This is only available while vmm-swap is enabled.
#[repr(C)]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default)]
pub struct SwapMetrics {
    /// count of pages on RAM.
    pub resident_pages: u64,
    /// count of pages copied from the vmm-swap file.
    pub copied_from_file_pages: u64,
    /// count of pages copied from the staging memory.
    pub copied_from_staging_pages: u64,
    /// count of pages initialized with zero.
    pub zeroed_pages: u64,
    /// count of pages which were already initialized on page faults. This can happen when several
    /// threads/processes access the uninitialized/removed page at the same time.
    pub redundant_pages: u64,
    /// count of pages in staging memory.
    pub staging_pages: u64,
    /// count of pages in swap files.
    pub swap_pages: u64,
}

/// The response to `crosvm swap status` command.
#[repr(C)]
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
pub struct SwapStatus {
    /// Current vmm-swap [SwapState].
    pub state: SwapState,
    /// Current [SwapMetrics] of vmm-swap.
    pub metrics: SwapMetrics,
    /// Latency and number of pages for current [SwapState]. See [SwapStateTransition] for details.
    pub state_transition: SwapStateTransition,
}

impl SwapStatus {
    /// Creates dummy [SwapStatus].
    pub fn dummy() -> Self {
        SwapStatus {
            state: SwapState::Pending,
            metrics: SwapMetrics::default(),
            state_transition: SwapStateTransition::default(),
        }
    }
}