vhost_user_backend, vmm: Close leaked file descriptors

Explicit call to 'close()' is required on file descriptors allocated
from 'epoll::create()', which is missing for the 'EpollContext' and
'VringWorker'. This patch enforces to close the file descriptors by
reusing the Drop trait of the 'File' struct.

Signed-off-by: Bo Chen <chen.bo@intel.com>
This commit is contained in:
Bo Chen 2020-05-15 11:31:35 -07:00 committed by Sebastien Boeuf
parent 35782bd9f8
commit 7c3e19c65a
2 changed files with 17 additions and 12 deletions

View File

@ -333,7 +333,7 @@ enum VringWorkerError {
type VringWorkerResult<T> = std::result::Result<T, VringWorkerError>; type VringWorkerResult<T> = std::result::Result<T, VringWorkerError>;
pub struct VringWorker { pub struct VringWorker {
epoll_fd: RawFd, epoll_file: File,
} }
impl VringWorker { impl VringWorker {
@ -342,7 +342,7 @@ impl VringWorker {
let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN]; let mut events = vec![epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN];
'epoll: loop { 'epoll: loop {
let num_events = match epoll::wait(self.epoll_fd, -1, &mut events[..]) { let num_events = match epoll::wait(self.epoll_file.as_raw_fd(), -1, &mut events[..]) {
Ok(res) => res, Ok(res) => res,
Err(e) => { Err(e) => {
if e.kind() == io::ErrorKind::Interrupted { if e.kind() == io::ErrorKind::Interrupted {
@ -396,7 +396,7 @@ impl VringWorker {
data: u64, data: u64,
) -> result::Result<(), io::Error> { ) -> result::Result<(), io::Error> {
epoll::ctl( epoll::ctl(
self.epoll_fd, self.epoll_file.as_raw_fd(),
epoll::ControlOptions::EPOLL_CTL_ADD, epoll::ControlOptions::EPOLL_CTL_ADD,
fd, fd,
epoll::Event::new(ev_type, data), epoll::Event::new(ev_type, data),
@ -413,7 +413,7 @@ impl VringWorker {
data: u64, data: u64,
) -> result::Result<(), io::Error> { ) -> result::Result<(), io::Error> {
epoll::ctl( epoll::ctl(
self.epoll_fd, self.epoll_file.as_raw_fd(),
epoll::ControlOptions::EPOLL_CTL_DEL, epoll::ControlOptions::EPOLL_CTL_DEL,
fd, fd,
epoll::Event::new(ev_type, data), epoll::Event::new(ev_type, data),
@ -486,8 +486,10 @@ impl<S: VhostUserBackend> VhostUserHandler<S> {
for (thread_id, queues_mask) in queues_per_thread.iter().enumerate() { for (thread_id, queues_mask) in queues_per_thread.iter().enumerate() {
// Create the epoll file descriptor // Create the epoll file descriptor
let epoll_fd = epoll::create(true).map_err(VhostUserHandlerError::EpollCreateFd)?; let epoll_fd = epoll::create(true).map_err(VhostUserHandlerError::EpollCreateFd)?;
// Use 'File' to enforce closing on 'epoll_fd'
let epoll_file = unsafe { File::from_raw_fd(epoll_fd) };
let vring_worker = Arc::new(VringWorker { epoll_fd }); let vring_worker = Arc::new(VringWorker { epoll_file });
let worker = vring_worker.clone(); let worker = vring_worker.clone();
let exit_event_id = if let Some((exit_event_fd, exit_event_id)) = let exit_event_id = if let Some((exit_event_fd, exit_event_id)) =

View File

@ -29,8 +29,9 @@ use crate::seccomp_filters::{get_seccomp_filter, Thread};
use crate::vm::{Error as VmError, Vm, VmState}; use crate::vm::{Error as VmError, Vm, VmState};
use libc::EFD_NONBLOCK; use libc::EFD_NONBLOCK;
use seccomp::{SeccompFilter, SeccompLevel}; use seccomp::{SeccompFilter, SeccompLevel};
use std::fs::File;
use std::io; use std::io;
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::mpsc::{Receiver, RecvError, SendError, Sender}; use std::sync::mpsc::{Receiver, RecvError, SendError, Sender};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@ -115,13 +116,15 @@ pub enum EpollDispatch {
} }
pub struct EpollContext { pub struct EpollContext {
raw_fd: RawFd, epoll_file: File,
dispatch_table: Vec<Option<EpollDispatch>>, dispatch_table: Vec<Option<EpollDispatch>>,
} }
impl EpollContext { impl EpollContext {
pub fn new() -> result::Result<EpollContext, io::Error> { pub fn new() -> result::Result<EpollContext, io::Error> {
let raw_fd = epoll::create(true)?; let epoll_fd = epoll::create(true)?;
// Use 'File' to enforce closing on 'epoll_fd'
let epoll_file = unsafe { File::from_raw_fd(epoll_fd) };
// Initial capacity needs to be large enough to hold: // Initial capacity needs to be large enough to hold:
// * 1 exit event // * 1 exit event
@ -132,7 +135,7 @@ impl EpollContext {
dispatch_table.push(None); dispatch_table.push(None);
Ok(EpollContext { Ok(EpollContext {
raw_fd, epoll_file,
dispatch_table, dispatch_table,
}) })
} }
@ -140,7 +143,7 @@ impl EpollContext {
pub fn add_stdin(&mut self) -> result::Result<(), io::Error> { pub fn add_stdin(&mut self) -> result::Result<(), io::Error> {
let dispatch_index = self.dispatch_table.len() as u64; let dispatch_index = self.dispatch_table.len() as u64;
epoll::ctl( epoll::ctl(
self.raw_fd, self.epoll_file.as_raw_fd(),
epoll::ControlOptions::EPOLL_CTL_ADD, epoll::ControlOptions::EPOLL_CTL_ADD,
libc::STDIN_FILENO, libc::STDIN_FILENO,
epoll::Event::new(epoll::Events::EPOLLIN, dispatch_index), epoll::Event::new(epoll::Events::EPOLLIN, dispatch_index),
@ -157,7 +160,7 @@ impl EpollContext {
{ {
let dispatch_index = self.dispatch_table.len() as u64; let dispatch_index = self.dispatch_table.len() as u64;
epoll::ctl( epoll::ctl(
self.raw_fd, self.epoll_file.as_raw_fd(),
epoll::ControlOptions::EPOLL_CTL_ADD, epoll::ControlOptions::EPOLL_CTL_ADD,
fd.as_raw_fd(), fd.as_raw_fd(),
epoll::Event::new(epoll::Events::EPOLLIN, dispatch_index), epoll::Event::new(epoll::Events::EPOLLIN, dispatch_index),
@ -170,7 +173,7 @@ impl EpollContext {
impl AsRawFd for EpollContext { impl AsRawFd for EpollContext {
fn as_raw_fd(&self) -> RawFd { fn as_raw_fd(&self) -> RawFd {
self.raw_fd self.epoll_file.as_raw_fd()
} }
} }