From 072e980e0830665a469e3869b831c50f09d19298 Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Fri, 6 Mar 2026 09:23:11 -0800 Subject: [PATCH] vmm: serial_manager: Use OwnedFd for the epoll FD Replace the use of a conventional File for managing the lifetime. Signed-off-by: Rob Bradford --- vmm/src/serial_manager.rs | 44 ++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/vmm/src/serial_manager.rs b/vmm/src/serial_manager.rs index 6ba2b9537..27f359bec 100644 --- a/vmm/src/serial_manager.rs +++ b/vmm/src/serial_manager.rs @@ -6,6 +6,7 @@ use std::fs::File; use std::io::Read; use std::net::Shutdown; +use std::os::fd::OwnedFd; use std::os::unix::io::{AsRawFd, FromRawFd}; use std::os::unix::net::UnixStream; use std::panic::AssertUnwindSafe; @@ -113,7 +114,7 @@ pub struct SerialManager { serial: Arc>, #[cfg(target_arch = "aarch64")] serial: Arc>, - epoll_file: File, + epoll_fd: OwnedFd, transport: ConsoleTransport, kill_evt: EventFd, handle: Option>, @@ -208,13 +209,13 @@ impl SerialManager { .set_out(Some(Box::new(buffer))); } - // Use 'File' to enforce closing on 'epoll_fd' + // Use 'OwnedFd' to manage lifetime // SAFETY: epoll_fd is valid - let epoll_file = unsafe { File::from_raw_fd(epoll_fd) }; + let epoll_fd = unsafe { OwnedFd::from_raw_fd(epoll_fd) }; Ok(Some(SerialManager { serial, - epoll_file, + epoll_fd, transport, kill_evt, handle: None, @@ -256,7 +257,7 @@ impl SerialManager { return Ok(()); } - let epoll_fd = self.epoll_file.as_raw_fd(); + let epoll_fd = self.epoll_fd.try_clone().map_err(Error::Epoll)?; let transport = self.transport.clone(); let serial = self.serial.clone(); let pty_write_out = self.pty_write_out.clone(); @@ -278,22 +279,23 @@ impl SerialManager { [epoll::Event::new(epoll::Events::empty(), 0); EPOLL_EVENTS_LEN]; loop { - let num_events = match epoll::wait(epoll_fd, timeout, &mut events[..]) { - Ok(res) => res, - 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; + let num_events = + match epoll::wait(epoll_fd.as_raw_fd(), timeout, &mut events[..]) { + Ok(res) => res, + 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; + } + return Err(Error::Epoll(e)); } - return Err(Error::Epoll(e)); - } - }; + }; if matches!(transport, ConsoleTransport::Pty(_)) && num_events == 0 { // This very specific case happens when the serial is connected @@ -332,7 +334,7 @@ impl SerialManager { unix_stream.try_clone().map_err(Error::CloneUnixStream)?; epoll::ctl( - epoll_fd, + epoll_fd.as_raw_fd(), epoll::ControlOptions::EPOLL_CTL_ADD, unix_stream.as_raw_fd(), epoll::Event::new(