vmm/devices/virtio/mem/
event_handler.rs

1// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use event_manager::{EventOps, Events, MutEventSubscriber};
5use vmm_sys_util::epoll::EventSet;
6
7use crate::devices::virtio::device::VirtioDevice;
8use crate::devices::virtio::mem::MEM_QUEUE;
9use crate::devices::virtio::mem::device::VirtioMem;
10use crate::logger::{error, warn};
11
12impl VirtioMem {
13    const PROCESS_ACTIVATE: u32 = 0;
14    const PROCESS_MEM_QUEUE: u32 = 1;
15
16    fn register_runtime_events(&self, ops: &mut EventOps) {
17        if let Err(err) = ops.add(Events::with_data(
18            &self.queue_events()[MEM_QUEUE],
19            Self::PROCESS_MEM_QUEUE,
20            EventSet::IN,
21        )) {
22            error!("virtio-mem: Failed to register queue event: {err}");
23        }
24    }
25
26    fn register_activate_event(&self, ops: &mut EventOps) {
27        if let Err(err) = ops.add(Events::with_data(
28            self.activate_event(),
29            Self::PROCESS_ACTIVATE,
30            EventSet::IN,
31        )) {
32            error!("virtio-mem: Failed to register activate event: {err}");
33        }
34    }
35
36    fn process_activate_event(&self, ops: &mut EventOps) {
37        if let Err(err) = self.activate_event().read() {
38            error!("virtio-mem: Failed to consume activate event: {err}");
39        }
40
41        // Register runtime events
42        self.register_runtime_events(ops);
43
44        // Remove activate event
45        if let Err(err) = ops.remove(Events::with_data(
46            self.activate_event(),
47            Self::PROCESS_ACTIVATE,
48            EventSet::IN,
49        )) {
50            error!("virtio-mem: Failed to un-register activate event: {err}");
51        }
52    }
53}
54
55impl MutEventSubscriber for VirtioMem {
56    fn init(&mut self, ops: &mut event_manager::EventOps) {
57        // This function can be called during different points in the device lifetime:
58        //  - shortly after device creation,
59        //  - on device activation (is-activated already true at this point),
60        //  - on device restore from snapshot.
61        if self.is_activated() {
62            self.register_runtime_events(ops);
63        } else {
64            self.register_activate_event(ops);
65        }
66    }
67
68    fn process(&mut self, events: event_manager::Events, ops: &mut event_manager::EventOps) {
69        let event_set = events.event_set();
70        let source = events.data();
71
72        if !event_set.contains(EventSet::IN) {
73            warn!("virtio-mem: Received unknown event: {event_set:?} from source {source}");
74            return;
75        }
76
77        if !self.is_activated() {
78            warn!("virtio-mem: The device is not activated yet. Spurious event received: {source}");
79            return;
80        }
81
82        match source {
83            Self::PROCESS_ACTIVATE => self.process_activate_event(ops),
84            Self::PROCESS_MEM_QUEUE => self.process_mem_queue_event(),
85
86            _ => {
87                warn!("virtio-mem: Unknown event received: {source}");
88            }
89        }
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use std::sync::{Arc, Mutex};
96
97    use event_manager::{EventManager, SubscriberOps};
98    use vmm_sys_util::epoll::EventSet;
99
100    use super::*;
101    use crate::devices::virtio::ActivateError;
102    use crate::devices::virtio::generated::virtio_mem::VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE;
103    use crate::devices::virtio::mem::device::test_utils::default_virtio_mem;
104    use crate::devices::virtio::test_utils::{VirtQueue, default_interrupt, default_mem};
105    use crate::vstate::memory::GuestAddress;
106
107    #[test]
108    fn test_event_handler_activation() {
109        let mut event_manager = EventManager::new().unwrap();
110        let mut mem_device = default_virtio_mem();
111        let mem = default_mem();
112        let interrupt = default_interrupt();
113
114        // Set up queue
115        let virtq = VirtQueue::new(GuestAddress(0), &mem, 16);
116        mem_device.queues_mut()[MEM_QUEUE] = virtq.create_queue();
117
118        let mem_device = Arc::new(Mutex::new(mem_device));
119        let _id = event_manager.add_subscriber(mem_device.clone());
120
121        // Device should register activate event when inactive
122        assert!(!mem_device.lock().unwrap().is_activated());
123
124        // Device should prevent activation before features are acked
125        let err = mem_device
126            .lock()
127            .unwrap()
128            .activate(mem.clone(), interrupt.clone())
129            .unwrap_err();
130
131        assert!(matches!(err, ActivateError::RequiredFeatureNotAcked(_)));
132
133        // Ack the feature and activate the device
134        mem_device
135            .lock()
136            .unwrap()
137            .set_acked_features(1 << VIRTIO_MEM_F_UNPLUGGED_INACCESSIBLE);
138
139        mem_device.lock().unwrap().activate(mem, interrupt).unwrap();
140
141        // Process activation event
142        let ev_count = event_manager.run_with_timeout(50).unwrap();
143        assert_eq!(ev_count, 1);
144        assert!(mem_device.lock().unwrap().is_activated());
145    }
146
147    #[test]
148    fn test_process_mem_queue_event() {
149        let mut event_manager = EventManager::new().unwrap();
150        let mut mem_device = default_virtio_mem();
151        let mem = default_mem();
152        let interrupt = default_interrupt();
153
154        // Set up queue
155        let virtq = VirtQueue::new(GuestAddress(0), &mem, 16);
156        mem_device.queues_mut()[MEM_QUEUE] = virtq.create_queue();
157        mem_device.set_acked_features(mem_device.avail_features());
158
159        let mem_device = Arc::new(Mutex::new(mem_device));
160        let _id = event_manager.add_subscriber(mem_device.clone());
161
162        // Activate device first
163        mem_device.lock().unwrap().activate(mem, interrupt).unwrap();
164        event_manager.run_with_timeout(50).unwrap(); // Process activation
165
166        // Trigger queue event
167        mem_device.lock().unwrap().queue_events()[MEM_QUEUE]
168            .write(1)
169            .unwrap();
170
171        // Process queue event
172        let ev_count = event_manager.run_with_timeout(50).unwrap();
173        assert_eq!(ev_count, 1);
174    }
175
176    #[test]
177    fn test_spurious_event_before_activation() {
178        let mut event_manager = EventManager::new().unwrap();
179        let mem_device = default_virtio_mem();
180        let mem_device = Arc::new(Mutex::new(mem_device));
181        let _id = event_manager.add_subscriber(mem_device.clone());
182
183        // Try to trigger queue event before activation
184        mem_device.lock().unwrap().queue_events()[MEM_QUEUE]
185            .write(1)
186            .unwrap();
187
188        // Should not process queue events before activation
189        let ev_count = event_manager.run_with_timeout(50).unwrap();
190        assert_eq!(ev_count, 0);
191    }
192}