vmm/devices/virtio/balloon/
event_handler.rs1use event_manager::{EventOps, Events, MutEventSubscriber};
5use vmm_sys_util::epoll::EventSet;
6
7use super::{DEFLATE_INDEX, INFLATE_INDEX, STATS_INDEX, report_balloon_event_fail};
8use crate::devices::virtio::balloon::device::Balloon;
9use crate::devices::virtio::device::VirtioDevice;
10use crate::logger::{error, warn};
11
12impl Balloon {
13 const PROCESS_ACTIVATE: u32 = 0;
14 const PROCESS_VIRTQ_INFLATE: u32 = 1;
15 const PROCESS_VIRTQ_DEFLATE: u32 = 2;
16 const PROCESS_VIRTQ_STATS: u32 = 3;
17 const PROCESS_STATS_TIMER: u32 = 4;
18 const PROCESS_VIRTQ_FREE_PAGE_HINTING: u32 = 5;
19 const PROCESS_VIRTQ_FREE_PAGE_REPORTING: u32 = 6;
20
21 fn register_runtime_events(&self, ops: &mut EventOps) {
22 if let Err(err) = ops.add(Events::with_data(
23 &self.queue_evts[INFLATE_INDEX],
24 Self::PROCESS_VIRTQ_INFLATE,
25 EventSet::IN,
26 )) {
27 error!("Failed to register inflate queue event: {}", err);
28 }
29 if let Err(err) = ops.add(Events::with_data(
30 &self.queue_evts[DEFLATE_INDEX],
31 Self::PROCESS_VIRTQ_DEFLATE,
32 EventSet::IN,
33 )) {
34 error!("Failed to register deflate queue event: {}", err);
35 }
36 if self.stats_enabled() {
37 if let Err(err) = ops.add(Events::with_data(
38 &self.queue_evts[STATS_INDEX],
39 Self::PROCESS_VIRTQ_STATS,
40 EventSet::IN,
41 )) {
42 error!("Failed to register stats queue event: {}", err);
43 }
44 if let Err(err) = ops.add(Events::with_data(
45 &self.stats_timer,
46 Self::PROCESS_STATS_TIMER,
47 EventSet::IN,
48 )) {
49 error!("Failed to register stats timerfd event: {}", err);
50 }
51 }
52
53 if self.free_page_hinting()
54 && let Err(err) = ops.add(Events::with_data(
55 &self.queue_evts[self.free_page_hinting_idx()],
56 Self::PROCESS_VIRTQ_FREE_PAGE_HINTING,
57 EventSet::IN,
58 ))
59 {
60 error!("Failed to register free page hinting queue event: {}", err);
61 }
62
63 if self.free_page_reporting()
64 && let Err(err) = ops.add(Events::with_data(
65 &self.queue_evts[self.free_page_reporting_idx()],
66 Self::PROCESS_VIRTQ_FREE_PAGE_REPORTING,
67 EventSet::IN,
68 ))
69 {
70 error!(
71 "Failed to register free page reporting queue event: {}",
72 err
73 );
74 }
75 }
76
77 fn register_activate_event(&self, ops: &mut EventOps) {
78 if let Err(err) = ops.add(Events::with_data(
79 &self.activate_evt,
80 Self::PROCESS_ACTIVATE,
81 EventSet::IN,
82 )) {
83 error!("Failed to register activate event: {}", err);
84 }
85 }
86
87 fn process_activate_event(&self, ops: &mut EventOps) {
88 if let Err(err) = self.activate_evt.read() {
89 error!("Failed to consume balloon activate event: {:?}", err);
90 }
91 self.register_runtime_events(ops);
92 if let Err(err) = ops.remove(Events::with_data(
93 &self.activate_evt,
94 Self::PROCESS_ACTIVATE,
95 EventSet::IN,
96 )) {
97 error!("Failed to un-register activate event: {}", err);
98 }
99 }
100}
101
102impl MutEventSubscriber for Balloon {
103 fn process(&mut self, event: Events, ops: &mut EventOps) {
104 let source = event.data();
105 let event_set = event.event_set();
106 let supported_events = EventSet::IN;
107
108 if !supported_events.contains(event_set) {
109 warn!(
110 "Received unknown event: {:?} from source: {:?}",
111 event_set, source
112 );
113 return;
114 }
115
116 if self.is_activated() {
117 match source {
118 Self::PROCESS_ACTIVATE => self.process_activate_event(ops),
119 Self::PROCESS_VIRTQ_INFLATE => self
120 .process_inflate_queue_event()
121 .unwrap_or_else(report_balloon_event_fail),
122 Self::PROCESS_VIRTQ_DEFLATE => self
123 .process_deflate_queue_event()
124 .unwrap_or_else(report_balloon_event_fail),
125 Self::PROCESS_VIRTQ_STATS => self
126 .process_stats_queue_event()
127 .unwrap_or_else(report_balloon_event_fail),
128 Self::PROCESS_STATS_TIMER => self
129 .process_stats_timer_event()
130 .unwrap_or_else(report_balloon_event_fail),
131 Self::PROCESS_VIRTQ_FREE_PAGE_HINTING => self
132 .process_free_page_hinting_queue_event()
133 .unwrap_or_else(report_balloon_event_fail),
134 Self::PROCESS_VIRTQ_FREE_PAGE_REPORTING => self
135 .process_free_page_reporting_queue_event()
136 .unwrap_or_else(report_balloon_event_fail),
137 _ => {
138 warn!("Balloon: Spurious event received: {:?}", source);
139 }
140 };
141 } else {
142 warn!(
143 "Balloon: The device is not yet activated. Spurious event received: {:?}",
144 source
145 );
146 }
147 }
148
149 fn init(&mut self, ops: &mut EventOps) {
150 if self.is_activated() {
155 self.register_runtime_events(ops);
156 } else {
157 self.register_activate_event(ops);
158 }
159 }
160}
161
162#[cfg(test)]
163pub mod tests {
164 use std::sync::{Arc, Mutex};
165
166 use event_manager::{EventManager, SubscriberOps};
167
168 use super::*;
169 use crate::devices::virtio::balloon::test_utils::set_request;
170 use crate::devices::virtio::test_utils::{VirtQueue, default_interrupt, default_mem};
171 use crate::vstate::memory::GuestAddress;
172
173 #[test]
174 fn test_event_handler() {
175 let mut event_manager = EventManager::new().unwrap();
176 let mut balloon = Balloon::new(0, true, 10, false, false).unwrap();
177 let mem = default_mem();
178 let interrupt = default_interrupt();
179 let infq = VirtQueue::new(GuestAddress(0), &mem, 16);
180 balloon.set_queue(INFLATE_INDEX, infq.create_queue());
181 balloon.set_queue(DEFLATE_INDEX, infq.create_queue());
182 balloon.set_queue(STATS_INDEX, infq.create_queue());
183
184 let balloon = Arc::new(Mutex::new(balloon));
185 let _id = event_manager.add_subscriber(balloon.clone());
186
187 {
189 let addr = 0x100;
190 set_request(&infq, 0, addr, 4, 0);
191 balloon.lock().unwrap().queue_evts[INFLATE_INDEX]
192 .write(1)
193 .unwrap();
194 }
195
196 let ev_count = event_manager.run_with_timeout(50).unwrap();
199 assert_eq!(ev_count, 0);
200
201 {
203 let b = balloon.lock().unwrap();
204 b.queue_evts[INFLATE_INDEX].write(1).unwrap();
206 let ev_count = event_manager.run_with_timeout(50).unwrap();
208 assert_eq!(ev_count, 0);
210 assert_eq!(infq.used.idx.get(), 0);
211 }
212
213 balloon
215 .lock()
216 .unwrap()
217 .activate(mem.clone(), interrupt)
218 .unwrap();
219 let ev_count = event_manager.run_with_timeout(50).unwrap();
221 assert_eq!(ev_count, 1);
222
223 event_manager
225 .run_with_timeout(100)
226 .expect("Metrics event timeout or error.");
227 assert_eq!(infq.used.idx.get(), 1);
229 }
230}