1 // Copyright 2019 Intel Corporation. All Rights Reserved.
2 // Copyright 2019-2021 Alibaba Cloud. All rights reserved.
3 //
4 // SPDX-License-Identifier: Apache-2.0
5 
6 use std::fmt::{Display, Formatter};
7 use std::io::{self, Result};
8 use std::marker::PhantomData;
9 use std::os::unix::io::{AsRawFd, RawFd};
10 
11 use vm_memory::bitmap::Bitmap;
12 use vmm_sys_util::epoll::{ControlOperation, Epoll, EpollEvent, EventSet};
13 use vmm_sys_util::eventfd::EventFd;
14 
15 use super::backend::VhostUserBackend;
16 use super::vring::VringT;
17 use super::GM;
18 
19 /// Errors related to vring epoll event handling.
20 #[derive(Debug)]
21 pub enum VringEpollError {
22     /// Failed to create epoll file descriptor.
23     EpollCreateFd(io::Error),
24     /// Failed while waiting for events.
25     EpollWait(io::Error),
26     /// Could not register exit event
27     RegisterExitEvent(io::Error),
28     /// Failed to read the event from kick EventFd.
29     HandleEventReadKick(io::Error),
30     /// Failed to handle the event from the backend.
31     HandleEventBackendHandling(io::Error),
32 }
33 
34 impl Display for VringEpollError {
fmt(&self, f: &mut Formatter) -> std::fmt::Result35     fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
36         match self {
37             VringEpollError::EpollCreateFd(e) => write!(f, "cannot create epoll fd: {}", e),
38             VringEpollError::EpollWait(e) => write!(f, "failed to wait for epoll event: {}", e),
39             VringEpollError::RegisterExitEvent(e) => write!(f, "cannot register exit event: {}", e),
40             VringEpollError::HandleEventReadKick(e) => {
41                 write!(f, "cannot read vring kick event: {}", e)
42             }
43             VringEpollError::HandleEventBackendHandling(e) => {
44                 write!(f, "failed to handle epoll event: {}", e)
45             }
46         }
47     }
48 }
49 
50 impl std::error::Error for VringEpollError {}
51 
52 /// Result of vring epoll operations.
53 pub type VringEpollResult<T> = std::result::Result<T, VringEpollError>;
54 
55 /// Epoll event handler to manage and process epoll events for registered file descriptor.
56 ///
57 /// The `VringEpollHandler` structure provides interfaces to:
58 /// - add file descriptors to be monitored by the epoll fd
59 /// - remove registered file descriptors from the epoll fd
60 /// - run the event loop to handle pending events on the epoll fd
61 pub struct VringEpollHandler<S, V, B> {
62     epoll: Epoll,
63     backend: S,
64     vrings: Vec<V>,
65     thread_id: usize,
66     exit_event_fd: Option<EventFd>,
67     phantom: PhantomData<B>,
68 }
69 
70 impl<S, V, B> VringEpollHandler<S, V, B> {
71     /// Send `exit event` to break the event loop.
send_exit_event(&self)72     pub fn send_exit_event(&self) {
73         if let Some(eventfd) = self.exit_event_fd.as_ref() {
74             let _ = eventfd.write(1);
75         }
76     }
77 }
78 
79 impl<S, V, B> VringEpollHandler<S, V, B>
80 where
81     S: VhostUserBackend<V, B>,
82     V: VringT<GM<B>>,
83     B: Bitmap + 'static,
84 {
85     /// Create a `VringEpollHandler` instance.
new(backend: S, vrings: Vec<V>, thread_id: usize) -> VringEpollResult<Self>86     pub(crate) fn new(backend: S, vrings: Vec<V>, thread_id: usize) -> VringEpollResult<Self> {
87         let epoll = Epoll::new().map_err(VringEpollError::EpollCreateFd)?;
88         let exit_event_fd = backend.exit_event(thread_id);
89 
90         if let Some(exit_event_fd) = &exit_event_fd {
91             let id = backend.num_queues();
92             epoll
93                 .ctl(
94                     ControlOperation::Add,
95                     exit_event_fd.as_raw_fd(),
96                     EpollEvent::new(EventSet::IN, id as u64),
97                 )
98                 .map_err(VringEpollError::RegisterExitEvent)?;
99         }
100 
101         Ok(VringEpollHandler {
102             epoll,
103             backend,
104             vrings,
105             thread_id,
106             exit_event_fd,
107             phantom: PhantomData,
108         })
109     }
110 
111     /// Register an event into the epoll fd.
112     ///
113     /// When this event is later triggered, the backend implementation of `handle_event` will be
114     /// called.
register_listener(&self, fd: RawFd, ev_type: EventSet, data: u64) -> Result<()>115     pub fn register_listener(&self, fd: RawFd, ev_type: EventSet, data: u64) -> Result<()> {
116         // `data` range [0...num_queues] is reserved for queues and exit event.
117         if data <= self.backend.num_queues() as u64 {
118             Err(io::Error::from_raw_os_error(libc::EINVAL))
119         } else {
120             self.register_event(fd, ev_type, data)
121         }
122     }
123 
124     /// Unregister an event from the epoll fd.
125     ///
126     /// If the event is triggered after this function has been called, the event will be silently
127     /// dropped.
unregister_listener(&self, fd: RawFd, ev_type: EventSet, data: u64) -> Result<()>128     pub fn unregister_listener(&self, fd: RawFd, ev_type: EventSet, data: u64) -> Result<()> {
129         // `data` range [0...num_queues] is reserved for queues and exit event.
130         if data <= self.backend.num_queues() as u64 {
131             Err(io::Error::from_raw_os_error(libc::EINVAL))
132         } else {
133             self.unregister_event(fd, ev_type, data)
134         }
135     }
136 
register_event(&self, fd: RawFd, ev_type: EventSet, data: u64) -> Result<()>137     pub(crate) fn register_event(&self, fd: RawFd, ev_type: EventSet, data: u64) -> Result<()> {
138         self.epoll
139             .ctl(ControlOperation::Add, fd, EpollEvent::new(ev_type, data))
140     }
141 
unregister_event(&self, fd: RawFd, ev_type: EventSet, data: u64) -> Result<()>142     pub(crate) fn unregister_event(&self, fd: RawFd, ev_type: EventSet, data: u64) -> Result<()> {
143         self.epoll
144             .ctl(ControlOperation::Delete, fd, EpollEvent::new(ev_type, data))
145     }
146 
147     /// Run the event poll loop to handle all pending events on registered fds.
148     ///
149     /// The event loop will be terminated once an event is received from the `exit event fd`
150     /// associated with the backend.
run(&self) -> VringEpollResult<()>151     pub(crate) fn run(&self) -> VringEpollResult<()> {
152         const EPOLL_EVENTS_LEN: usize = 100;
153         let mut events = vec![EpollEvent::new(EventSet::empty(), 0); EPOLL_EVENTS_LEN];
154 
155         'epoll: loop {
156             let num_events = match self.epoll.wait(-1, &mut events[..]) {
157                 Ok(res) => res,
158                 Err(e) => {
159                     if e.kind() == io::ErrorKind::Interrupted {
160                         // It's well defined from the epoll_wait() syscall
161                         // documentation that the epoll loop can be interrupted
162                         // before any of the requested events occurred or the
163                         // timeout expired. In both those cases, epoll_wait()
164                         // returns an error of type EINTR, but this should not
165                         // be considered as a regular error. Instead it is more
166                         // appropriate to retry, by calling into epoll_wait().
167                         continue;
168                     }
169                     return Err(VringEpollError::EpollWait(e));
170                 }
171             };
172 
173             for event in events.iter().take(num_events) {
174                 let evset = match EventSet::from_bits(event.events) {
175                     Some(evset) => evset,
176                     None => {
177                         let evbits = event.events;
178                         println!("epoll: ignoring unknown event set: 0x{:x}", evbits);
179                         continue;
180                     }
181                 };
182 
183                 let ev_type = event.data() as u16;
184 
185                 // handle_event() returns true if an event is received from the exit event fd.
186                 if self.handle_event(ev_type, evset)? {
187                     break 'epoll;
188                 }
189             }
190         }
191 
192         Ok(())
193     }
194 
handle_event(&self, device_event: u16, evset: EventSet) -> VringEpollResult<bool>195     fn handle_event(&self, device_event: u16, evset: EventSet) -> VringEpollResult<bool> {
196         if self.exit_event_fd.is_some() && device_event as usize == self.backend.num_queues() {
197             return Ok(true);
198         }
199 
200         if (device_event as usize) < self.vrings.len() {
201             let vring = &self.vrings[device_event as usize];
202             let enabled = vring
203                 .read_kick()
204                 .map_err(VringEpollError::HandleEventReadKick)?;
205 
206             // If the vring is not enabled, it should not be processed.
207             if !enabled {
208                 return Ok(false);
209             }
210         }
211 
212         self.backend
213             .handle_event(device_event, evset, &self.vrings, self.thread_id)
214             .map_err(VringEpollError::HandleEventBackendHandling)
215     }
216 }
217 
218 impl<S, V, B> AsRawFd for VringEpollHandler<S, V, B> {
as_raw_fd(&self) -> RawFd219     fn as_raw_fd(&self) -> RawFd {
220         self.epoll.as_raw_fd()
221     }
222 }
223 
224 #[cfg(test)]
225 mod tests {
226     use super::super::backend::tests::MockVhostBackend;
227     use super::super::vring::VringRwLock;
228     use super::*;
229     use std::sync::{Arc, Mutex};
230     use vm_memory::{GuestAddress, GuestMemoryAtomic, GuestMemoryMmap};
231     use vmm_sys_util::eventfd::EventFd;
232 
233     #[test]
test_vring_epoll_handler()234     fn test_vring_epoll_handler() {
235         let mem = GuestMemoryAtomic::new(
236             GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0x100000), 0x10000)]).unwrap(),
237         );
238         let vring = VringRwLock::new(mem, 0x1000).unwrap();
239         let backend = Arc::new(Mutex::new(MockVhostBackend::new()));
240 
241         let handler = VringEpollHandler::new(backend, vec![vring], 0x1).unwrap();
242 
243         let eventfd = EventFd::new(0).unwrap();
244         handler
245             .register_listener(eventfd.as_raw_fd(), EventSet::IN, 3)
246             .unwrap();
247         // Register an already registered fd.
248         handler
249             .register_listener(eventfd.as_raw_fd(), EventSet::IN, 3)
250             .unwrap_err();
251         // Register an invalid data.
252         handler
253             .register_listener(eventfd.as_raw_fd(), EventSet::IN, 1)
254             .unwrap_err();
255 
256         handler
257             .unregister_listener(eventfd.as_raw_fd(), EventSet::IN, 3)
258             .unwrap();
259         // unregister an already unregistered fd.
260         handler
261             .unregister_listener(eventfd.as_raw_fd(), EventSet::IN, 3)
262             .unwrap_err();
263         // unregister an invalid data.
264         handler
265             .unregister_listener(eventfd.as_raw_fd(), EventSet::IN, 1)
266             .unwrap_err();
267         // Check we retrieve the correct file descriptor
268         assert_eq!(handler.as_raw_fd(), handler.epoll.as_raw_fd());
269     }
270 }
271