From 56d7c04226ecb7629d874da7c0443a08e5ff4f2d Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Tue, 4 Feb 2020 17:11:46 +0100 Subject: [PATCH] vm-virtio: vsock: Don't return error when epoll_wait is interrupted The existing code taking care of the epoll loop was too restrictive as it was considering all errors the same. But in case the error is EINTR, this means the syscall has been interrupted while waiting, and it should be resumed to wait again. This patch enforces the parsing of the returned error and prevent the code from assuming EINTR should be handled as all other errors. Signed-off-by: Sebastien Boeuf --- vm-virtio/src/vsock/unix/muxer.rs | 43 ++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/vm-virtio/src/vsock/unix/muxer.rs b/vm-virtio/src/vsock/unix/muxer.rs index 7862190f1..e0af9b9ff 100644 --- a/vm-virtio/src/vsock/unix/muxer.rs +++ b/vm-virtio/src/vsock/unix/muxer.rs @@ -32,7 +32,7 @@ /// mapping `RawFd`s to `EpollListener`s. /// use std::collections::{HashMap, HashSet}; -use std::io::Read; +use std::io::{self, Read}; use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::net::{UnixListener, UnixStream}; @@ -285,22 +285,35 @@ impl VsockEpollListener for VsockMuxer { debug!("vsock: muxer received kick"); let mut epoll_events = vec![epoll::Event::new(epoll::Events::empty(), 0); 32]; - match epoll::wait(self.epoll_fd, 0, epoll_events.as_mut_slice()) { - Ok(ev_cnt) => { - #[allow(clippy::needless_range_loop)] - for i in 0..ev_cnt { - self.handle_event( - epoll_events[i].data as RawFd, - // It's ok to unwrap here, since the `epoll_events[i].events` is filled - // in by `epoll::wait()`, and therefore contains only valid epoll - // flags. - epoll::Events::from_bits(epoll_events[i].events).unwrap(), - ); + 'epoll: loop { + match epoll::wait(self.epoll_fd, 0, epoll_events.as_mut_slice()) { + Ok(ev_cnt) => { + #[allow(clippy::needless_range_loop)] + for i in 0..ev_cnt { + self.handle_event( + epoll_events[i].data as RawFd, + // It's ok to unwrap here, since the `epoll_events[i].events` is filled + // in by `epoll::wait()`, and therefore contains only valid epoll + // flags. + epoll::Events::from_bits(epoll_events[i].events).unwrap(), + ); + } + } + Err(e) => { + if e.kind() == io::ErrorKind::Interrupted { + // It's well defined from the epoll_wait() syscall + // documentation that the epoll loop can be interrupted + // before any of the requested events occurred or the + // timeout expired. In both those cases, epoll_wait() + // returns an error of type EINTR, but this should not + // be considered as a regular error. Instead it is more + // appropriate to retry, by calling into epoll_wait(). + continue; + } + warn!("vsock: failed to consume muxer epoll event: {}", e); } } - Err(e) => { - warn!("vsock: failed to consume muxer epoll event: {}", e); - } + break 'epoll; } } }