From 35782bd9f8e8c39eaaaebc8a4059be6de6f6143b Mon Sep 17 00:00:00 2001 From: Bo Chen Date: Thu, 14 May 2020 19:25:54 -0700 Subject: [PATCH] vm-virtio: Close file descriptors created by epoll::create() This patch fixes file descriptor leak related to epoll::create() from various virtio devices. Fixes: #1124 Signed-off-by: Bo Chen --- vm-virtio/src/block.rs | 12 +++++++----- vm-virtio/src/console.rs | 19 +++++++++++-------- vm-virtio/src/iommu.rs | 15 +++++++++------ vm-virtio/src/mem.rs | 15 +++++++++------ vm-virtio/src/net.rs | 19 +++++++++++-------- vm-virtio/src/net_util.rs | 13 ++++++++----- vm-virtio/src/pmem.rs | 12 +++++++----- vm-virtio/src/rng.rs | 12 +++++++----- vm-virtio/src/vhost_user/handler.rs | 15 +++++++++------ vm-virtio/src/vsock/device.rs | 19 +++++++++++-------- vm-virtio/src/vsock/unix/muxer.rs | 23 +++++++++++++---------- 11 files changed, 102 insertions(+), 72 deletions(-) diff --git a/vm-virtio/src/block.rs b/vm-virtio/src/block.rs index ed8d6885e..b009ba41d 100755 --- a/vm-virtio/src/block.rs +++ b/vm-virtio/src/block.rs @@ -26,7 +26,7 @@ use std::io::{self, Read, Seek, SeekFrom, Write}; use std::num::Wrapping; use std::ops::DerefMut; use std::os::linux::fs::MetadataExt; -use std::os::unix::io::{AsRawFd, RawFd}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::path::PathBuf; use std::result; use std::slice; @@ -708,24 +708,26 @@ impl BlockEpollHandler { ) -> result::Result<(), DeviceError> { // Create the epoll file descriptor let epoll_fd = epoll::create(true).map_err(DeviceError::EpollCreateFd)?; + // Use 'File' to enforce closing on 'epoll_fd' + let epoll_file = unsafe { File::from_raw_fd(epoll_fd) }; // Add events epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, queue_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(QUEUE_AVAIL_EVENT)), ) .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.kill_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(KILL_EVENT)), ) .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.pause_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(PAUSE_EVENT)), @@ -736,7 +738,7 @@ impl BlockEpollHandler { let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN]; 'epoll: loop { - let num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) { + let num_events = match epoll::wait(epoll_file.as_raw_fd(), -1, &mut events[..]) { Ok(res) => res, Err(e) => { if e.kind() == io::ErrorKind::Interrupted { diff --git a/vm-virtio/src/console.rs b/vm-virtio/src/console.rs index 1201663be..3ee1189bc 100755 --- a/vm-virtio/src/console.rs +++ b/vm-virtio/src/console.rs @@ -14,10 +14,11 @@ use serde::ser::{Serialize, SerializeStruct, Serializer}; use std; use std::cmp; use std::collections::VecDeque; +use std::fs::File; use std::io; use std::io::Write; use std::ops::DerefMut; -use std::os::unix::io::AsRawFd; +use std::os::unix::io::{AsRawFd, FromRawFd}; use std::result; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::{Arc, Mutex}; @@ -186,31 +187,33 @@ impl ConsoleEpollHandler { fn run(&mut self, paused: Arc) -> result::Result<(), DeviceError> { // Create the epoll file descriptor let epoll_fd = epoll::create(true).map_err(DeviceError::EpollCreateFd)?; + // Use 'File' to enforce closing on 'epoll_fd' + let epoll_file = unsafe { File::from_raw_fd(epoll_fd) }; // Add events epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.input_queue_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(INPUT_QUEUE_EVENT)), ) .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.output_queue_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(OUTPUT_QUEUE_EVENT)), ) .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.input_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(INPUT_EVENT)), ) .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.config_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(CONFIG_EVENT)), @@ -218,14 +221,14 @@ impl ConsoleEpollHandler { .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.kill_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(KILL_EVENT)), ) .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.pause_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(PAUSE_EVENT)), @@ -236,7 +239,7 @@ impl ConsoleEpollHandler { let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN]; 'epoll: loop { - let num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) { + let num_events = match epoll::wait(epoll_file.as_raw_fd(), -1, &mut events[..]) { Ok(res) => res, Err(e) => { if e.kind() == io::ErrorKind::Interrupted { diff --git a/vm-virtio/src/iommu.rs b/vm-virtio/src/iommu.rs index 612a087f6..1a5399132 100644 --- a/vm-virtio/src/iommu.rs +++ b/vm-virtio/src/iommu.rs @@ -13,10 +13,11 @@ use libc::EFD_NONBLOCK; use std::cmp; use std::collections::BTreeMap; use std::fmt::{self, Display}; +use std::fs::File; use std::io::{self, Write}; use std::mem::size_of; use std::ops::Bound::Included; -use std::os::unix::io::AsRawFd; +use std::os::unix::io::{AsRawFd, FromRawFd}; use std::result; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, RwLock}; @@ -647,31 +648,33 @@ impl IommuEpollHandler { fn run(&mut self, paused: Arc) -> result::Result<(), DeviceError> { // Create the epoll file descriptor let epoll_fd = epoll::create(true).map_err(DeviceError::EpollCreateFd)?; + // Use 'File' to enforce closing on 'epoll_fd' + let epoll_file = unsafe { File::from_raw_fd(epoll_fd) }; // Add events epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.queue_evts[0].as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(REQUEST_Q_EVENT)), ) .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.queue_evts[1].as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(EVENT_Q_EVENT)), ) .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.kill_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(KILL_EVENT)), ) .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.pause_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(PAUSE_EVENT)), @@ -682,7 +685,7 @@ impl IommuEpollHandler { let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN]; 'epoll: loop { - let num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) { + let num_events = match epoll::wait(epoll_file.as_raw_fd(), -1, &mut events[..]) { Ok(res) => res, Err(e) => { if e.kind() == io::ErrorKind::Interrupted { diff --git a/vm-virtio/src/mem.rs b/vm-virtio/src/mem.rs index b0b56357b..2d80e1a7b 100644 --- a/vm-virtio/src/mem.rs +++ b/vm-virtio/src/mem.rs @@ -22,9 +22,10 @@ use epoll; use libc; use libc::EFD_NONBLOCK; use std::cmp; +use std::fs::File; use std::io::{self, Write}; use std::mem::size_of; -use std::os::unix::io::{AsRawFd, RawFd}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::result; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::mpsc; @@ -596,10 +597,12 @@ impl MemEpollHandler { fn run(&mut self, paused: Arc) -> result::Result<(), DeviceError> { // Create the epoll file descriptor let epoll_fd = epoll::create(true).map_err(DeviceError::EpollCreateFd)?; + // Use 'File' to enforce closing on 'epoll_fd' + let epoll_file = unsafe { File::from_raw_fd(epoll_fd) }; // Add events epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.resize.evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(RESIZE_EVENT)), @@ -607,7 +610,7 @@ impl MemEpollHandler { .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.queue_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(QUEUE_AVAIL_EVENT)), @@ -615,7 +618,7 @@ impl MemEpollHandler { .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.kill_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(KILL_EVENT)), @@ -623,7 +626,7 @@ impl MemEpollHandler { .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.pause_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(PAUSE_EVENT)), @@ -634,7 +637,7 @@ impl MemEpollHandler { let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN]; 'epoll: loop { - let num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) { + let num_events = match epoll::wait(epoll_file.as_raw_fd(), -1, &mut events[..]) { Ok(res) => res, Err(e) => { if e.kind() == io::ErrorKind::Interrupted { diff --git a/vm-virtio/src/net.rs b/vm-virtio/src/net.rs index 3b04ba5fb..2daa9fee8 100644 --- a/vm-virtio/src/net.rs +++ b/vm-virtio/src/net.rs @@ -21,10 +21,11 @@ use libc::EAGAIN; use libc::EFD_NONBLOCK; use net_util::{MacAddr, Tap}; use std::cmp; +use std::fs::File; use std::io::Read; use std::io::{self, Write}; use std::net::Ipv4Addr; -use std::os::unix::io::{AsRawFd, RawFd}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::result; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; @@ -206,31 +207,33 @@ impl NetEpollHandler { ) -> result::Result<(), DeviceError> { // Create the epoll file descriptor self.epoll_fd = epoll::create(true).map_err(DeviceError::EpollCreateFd)?; - // Add events + // Use 'File' to enforce closing on 'epoll_fd' + let epoll_file = unsafe { File::from_raw_fd(self.epoll_fd) }; + // Add events epoll::ctl( - self.epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, queue_evts[0].as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(RX_QUEUE_EVENT)), ) .map_err(DeviceError::EpollCtl)?; epoll::ctl( - self.epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, queue_evts[1].as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(TX_QUEUE_EVENT)), ) .map_err(DeviceError::EpollCtl)?; epoll::ctl( - self.epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.kill_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(KILL_EVENT)), ) .map_err(DeviceError::EpollCtl)?; epoll::ctl( - self.epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.pause_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(PAUSE_EVENT)), @@ -241,7 +244,7 @@ impl NetEpollHandler { // then we can start the thread while listening onto the TAP. if queues[0].available_descriptors(&self.mem.memory()).unwrap() { epoll::ctl( - self.epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.tap.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(RX_TAP_EVENT)), @@ -253,7 +256,7 @@ impl NetEpollHandler { let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); NET_EVENTS_COUNT]; 'epoll: loop { - let num_events = match epoll::wait(self.epoll_fd, -1, &mut events[..]) { + let num_events = match epoll::wait(epoll_file.as_raw_fd(), -1, &mut events[..]) { Ok(res) => res, Err(e) => { if e.kind() == io::ErrorKind::Interrupted { diff --git a/vm-virtio/src/net_util.rs b/vm-virtio/src/net_util.rs index dfe04b83d..bf332586e 100644 --- a/vm-virtio/src/net_util.rs +++ b/vm-virtio/src/net_util.rs @@ -8,10 +8,11 @@ use net_util::{MacAddr, Tap, TapError}; use serde::ser::{Serialize, SerializeStruct, Serializer}; use std::cmp; use std::fs; +use std::fs::File; use std::io::{self, Write}; use std::mem; use std::net::Ipv4Addr; -use std::os::unix::io::{AsRawFd, RawFd}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::path::Path; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; @@ -247,23 +248,25 @@ impl NetCtrlEpollHandler { pub fn run_ctrl(&mut self, paused: Arc) -> std::result::Result<(), DeviceError> { // Create the epoll file descriptor self.epoll_fd = epoll::create(true).map_err(DeviceError::EpollCreateFd)?; + // Use 'File' to enforce closing on 'epoll_fd' + let epoll_file = unsafe { File::from_raw_fd(self.epoll_fd) }; register_listener( - self.epoll_fd, + epoll_file.as_raw_fd(), self.ctrl_q.queue_evt.as_raw_fd(), epoll::Events::EPOLLIN, u64::from(CTRL_QUEUE_EVENT), ) .unwrap(); register_listener( - self.epoll_fd, + epoll_file.as_raw_fd(), self.kill_evt.as_raw_fd(), epoll::Events::EPOLLIN, u64::from(KILL_EVENT), ) .unwrap(); register_listener( - self.epoll_fd, + epoll_file.as_raw_fd(), self.pause_evt.as_raw_fd(), epoll::Events::EPOLLIN, u64::from(PAUSE_EVENT), @@ -273,7 +276,7 @@ impl NetCtrlEpollHandler { let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); CTRL_EVENT_COUNT]; 'epoll: loop { - let num_events = match epoll::wait(self.epoll_fd, -1, &mut events[..]) { + let num_events = match epoll::wait(epoll_file.as_raw_fd(), -1, &mut events[..]) { Ok(res) => res, Err(e) => { if e.kind() == std::io::ErrorKind::Interrupted { diff --git a/vm-virtio/src/pmem.rs b/vm-virtio/src/pmem.rs index d14ab0a82..ae1a638b5 100644 --- a/vm-virtio/src/pmem.rs +++ b/vm-virtio/src/pmem.rs @@ -21,7 +21,7 @@ use std::fmt::{self, Display}; use std::fs::File; use std::io::{self, Write}; use std::mem::size_of; -use std::os::unix::io::AsRawFd; +use std::os::unix::io::{AsRawFd, FromRawFd}; use std::result; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; @@ -249,17 +249,19 @@ impl PmemEpollHandler { fn run(&mut self, paused: Arc) -> result::Result<(), DeviceError> { // Create the epoll file descriptor let epoll_fd = epoll::create(true).map_err(DeviceError::EpollCreateFd)?; + // Use 'File' to enforce closing on 'epoll_fd' + let epoll_file = unsafe { File::from_raw_fd(epoll_fd) }; // Add events epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.queue_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(QUEUE_AVAIL_EVENT)), ) .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.kill_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(KILL_EVENT)), @@ -267,7 +269,7 @@ impl PmemEpollHandler { .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.pause_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(PAUSE_EVENT)), @@ -278,7 +280,7 @@ impl PmemEpollHandler { let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN]; 'epoll: loop { - let num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) { + let num_events = match epoll::wait(epoll_file.as_raw_fd(), -1, &mut events[..]) { Ok(res) => res, Err(e) => { if e.kind() == io::ErrorKind::Interrupted { diff --git a/vm-virtio/src/rng.rs b/vm-virtio/src/rng.rs index 21ab347ed..b89511f10 100755 --- a/vm-virtio/src/rng.rs +++ b/vm-virtio/src/rng.rs @@ -14,7 +14,7 @@ use libc::EFD_NONBLOCK; use std; use std::fs::File; use std::io; -use std::os::unix::io::AsRawFd; +use std::os::unix::io::{AsRawFd, FromRawFd}; use std::result; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; @@ -94,24 +94,26 @@ impl RngEpollHandler { fn run(&mut self, paused: Arc) -> result::Result<(), DeviceError> { // Create the epoll file descriptor let epoll_fd = epoll::create(true).map_err(DeviceError::EpollCreateFd)?; + // Use 'File' to enforce closing on 'epoll_fd' + let epoll_file = unsafe { File::from_raw_fd(epoll_fd) }; // Add events epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.queue_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(QUEUE_AVAIL_EVENT)), ) .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.kill_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(KILL_EVENT)), ) .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.pause_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(PAUSE_EVENT)), @@ -122,7 +124,7 @@ impl RngEpollHandler { let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN]; 'epoll: loop { - let num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) { + let num_events = match epoll::wait(epoll_file.as_raw_fd(), -1, &mut events[..]) { Ok(res) => res, Err(e) => { if e.kind() == io::ErrorKind::Interrupted { diff --git a/vm-virtio/src/vhost_user/handler.rs b/vm-virtio/src/vhost_user/handler.rs index c7fa06ddd..6b01ae995 100644 --- a/vm-virtio/src/vhost_user/handler.rs +++ b/vm-virtio/src/vhost_user/handler.rs @@ -13,8 +13,9 @@ use epoll; use vmm_sys_util::eventfd::EventFd; use crate::VirtioInterrupt; +use std::fs::File; use std::io; -use std::os::unix::io::AsRawFd; +use std::os::unix::io::{AsRawFd, FromRawFd}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use std::thread; @@ -61,13 +62,15 @@ impl VhostUserEpollHandler { pub fn run(&mut self, paused: Arc) -> Result<()> { // Create the epoll file descriptor let epoll_fd = epoll::create(true).map_err(Error::EpollCreateFd)?; + // Use 'File' to enforce closing on 'epoll_fd' + let epoll_file = unsafe { File::from_raw_fd(epoll_fd) }; for (index, vhost_user_interrupt) in self.vu_epoll_cfg.vu_interrupt_list.iter().enumerate() { if let Some(eventfd) = &vhost_user_interrupt.0 { // Add events epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, eventfd.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, index as u64), @@ -79,7 +82,7 @@ impl VhostUserEpollHandler { let kill_evt_index = self.vu_epoll_cfg.vu_interrupt_list.len(); epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.vu_epoll_cfg.kill_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, kill_evt_index as u64), @@ -89,7 +92,7 @@ impl VhostUserEpollHandler { let pause_evt_index = kill_evt_index + 1; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.vu_epoll_cfg.pause_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, pause_evt_index as u64), @@ -101,7 +104,7 @@ impl VhostUserEpollHandler { let slave_evt_index = if let Some(self_req_handler) = &self.vu_epoll_cfg.slave_req_handler { index = pause_evt_index + 1; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self_req_handler.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, index as u64), @@ -116,7 +119,7 @@ impl VhostUserEpollHandler { let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); index + 1]; 'poll: loop { - let num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) { + let num_events = match epoll::wait(epoll_file.as_raw_fd(), -1, &mut events[..]) { Ok(res) => res, Err(e) => { if e.kind() == io::ErrorKind::Interrupted { diff --git a/vm-virtio/src/vsock/device.rs b/vm-virtio/src/vsock/device.rs index b6a818db9..9f5dc0023 100644 --- a/vm-virtio/src/vsock/device.rs +++ b/vm-virtio/src/vsock/device.rs @@ -38,8 +38,9 @@ use byteorder::{ByteOrder, LittleEndian}; use epoll; use libc::EFD_NONBLOCK; use std; +use std::fs::File; use std::io; -use std::os::unix::io::AsRawFd; +use std::os::unix::io::{AsRawFd, FromRawFd}; use std::path::PathBuf; use std::result; use std::sync::atomic::{AtomicBool, Ordering}; @@ -198,31 +199,33 @@ where fn run(&mut self, paused: Arc) -> result::Result<(), DeviceError> { // Create the epoll file descriptor let epoll_fd = epoll::create(true).map_err(DeviceError::EpollCreateFd)?; + // Use 'File' to enforce closing on 'epoll_fd' + let epoll_file = unsafe { File::from_raw_fd(epoll_fd) }; // Add events epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.queue_evts[0].as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(RX_QUEUE_EVENT)), ) .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.queue_evts[1].as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(TX_QUEUE_EVENT)), ) .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.queue_evts[2].as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(EVT_QUEUE_EVENT)), ) .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.backend.read().unwrap().get_polled_fd(), epoll::Event::new( @@ -232,14 +235,14 @@ where ) .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.kill_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(KILL_EVENT)), ) .map_err(DeviceError::EpollCtl)?; epoll::ctl( - epoll_fd, + epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, self.pause_evt.as_raw_fd(), epoll::Event::new(epoll::Events::EPOLLIN, u64::from(PAUSE_EVENT)), @@ -249,7 +252,7 @@ where let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); EVENTS_LEN]; 'epoll: loop { - let num_events = match epoll::wait(epoll_fd, -1, &mut events[..]) { + let num_events = match epoll::wait(epoll_file.as_raw_fd(), -1, &mut events[..]) { Ok(res) => res, Err(e) => { if e.kind() == io::ErrorKind::Interrupted { diff --git a/vm-virtio/src/vsock/unix/muxer.rs b/vm-virtio/src/vsock/unix/muxer.rs index e0af9b9ff..9cf1af9bf 100644 --- a/vm-virtio/src/vsock/unix/muxer.rs +++ b/vm-virtio/src/vsock/unix/muxer.rs @@ -32,8 +32,9 @@ /// mapping `RawFd`s to `EpollListener`s. /// use std::collections::{HashMap, HashSet}; +use std::fs::File; use std::io::{self, Read}; -use std::os::unix::io::{AsRawFd, RawFd}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::os::unix::net::{UnixListener, UnixStream}; use super::super::csm::ConnState; @@ -107,8 +108,8 @@ pub struct VsockMuxer { /// The file system path of the host-side Unix socket. This is used to figure out the path /// to Unix sockets listening on specific ports. I.e. "_". host_sock_path: String, - /// The nested epoll FD, used to register epoll listeners. - epoll_fd: RawFd, + /// The nested epoll File, used to register epoll listeners. + epoll_file: File, /// A hash set used to keep track of used host-side (local) ports, in order to assign local /// ports to host-initiated connections. local_port_set: HashSet, @@ -267,7 +268,7 @@ impl VsockEpollListener for VsockMuxer { /// This will be the muxer's nested epoll FD. /// fn get_polled_fd(&self) -> RawFd { - self.epoll_fd + self.epoll_file.as_raw_fd() } /// Get the epoll events to be polled upstream. @@ -286,7 +287,7 @@ impl VsockEpollListener for VsockMuxer { let mut epoll_events = vec![epoll::Event::new(epoll::Events::empty(), 0); 32]; 'epoll: loop { - match epoll::wait(self.epoll_fd, 0, epoll_events.as_mut_slice()) { + match epoll::wait(self.epoll_file.as_raw_fd(), 0, epoll_events.as_mut_slice()) { Ok(ev_cnt) => { #[allow(clippy::needless_range_loop)] for i in 0..ev_cnt { @@ -327,6 +328,8 @@ impl VsockMuxer { // Create the nested epoll FD. This FD will be added to the VMM `EpollContext`, at // device activation time. let epoll_fd = epoll::create(true).map_err(Error::EpollFdCreate)?; + // Use 'File' to enforce closing on 'epoll_fd' + let epoll_file = unsafe { File::from_raw_fd(epoll_fd) }; // Open/bind/listen on the host Unix socket, so we can accept host-initiated // connections. @@ -338,7 +341,7 @@ impl VsockMuxer { cid, host_sock, host_sock_path, - epoll_fd, + epoll_file, rxq: MuxerRxQ::new(), conn_map: HashMap::with_capacity(defs::MAX_CONNECTIONS), listener_map: HashMap::with_capacity(defs::MAX_CONNECTIONS + 1), @@ -559,7 +562,7 @@ impl VsockMuxer { }; epoll::ctl( - self.epoll_fd, + self.epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, fd, epoll::Event::new(evset, fd as u64), @@ -580,7 +583,7 @@ impl VsockMuxer { if maybe_listener.is_some() { epoll::ctl( - self.epoll_fd, + self.epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_DEL, fd, epoll::Event::new(epoll::Events::empty(), 0), @@ -712,7 +715,7 @@ impl VsockMuxer { *evset = new_evset; epoll::ctl( - self.epoll_fd, + self.epoll_file.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_MOD, fd, epoll::Event::new(new_evset, fd as u64), @@ -979,7 +982,7 @@ mod tests { #[test] fn test_muxer_epoll_listener() { let ctx = MuxerTestContext::new("muxer_epoll_listener"); - assert_eq!(ctx.muxer.get_polled_fd(), ctx.muxer.epoll_fd); + assert_eq!(ctx.muxer.get_polled_fd(), ctx.muxer.epoll_file.as_raw_fd()); assert_eq!(ctx.muxer.get_polled_evset(), epoll::Events::EPOLLIN); }