From 4d2a4e2805c5ae49cfd0461093d1e97f522761dc Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Wed, 25 Aug 2021 12:30:49 +0100 Subject: [PATCH] vmm: Handle epoll events for PTYs separately Use two separate events for the console and serial PTY and then drive the handling of the inputs on the PTY separately. This results in the correct behaviour when both console and serial are attached to the PTY as they are triggered separately on the epoll so events are not lost. Fixes: #3012 Signed-off-by: Rob Bradford --- vmm/src/lib.rs | 11 ++++++----- vmm/src/vm.rs | 42 +++++++++++++++++++++++------------------- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/vmm/src/lib.rs b/vmm/src/lib.rs index 627cebe6d..fd1145ff4 100644 --- a/vmm/src/lib.rs +++ b/vmm/src/lib.rs @@ -148,7 +148,8 @@ pub enum EpollDispatch { Stdin, Api, ActivateVirtioDevices, - Pty, + ConsolePty, + SerialPty, } pub struct EpollContext { @@ -392,12 +393,12 @@ impl Vmm { )?; if let Some(serial_pty) = vm.serial_pty() { self.epoll - .add_event(&serial_pty.main, EpollDispatch::Pty) + .add_event(&serial_pty.main, EpollDispatch::SerialPty) .map_err(VmError::EventfdError)?; }; if let Some(console_pty) = vm.console_pty() { self.epoll - .add_event(&console_pty.main, EpollDispatch::Pty) + .add_event(&console_pty.main, EpollDispatch::ConsolePty) .map_err(VmError::EventfdError)?; }; self.vm = Some(vm); @@ -1295,9 +1296,9 @@ impl Vmm { .map_err(Error::ActivateVirtioDevices)?; } } - EpollDispatch::Pty => { + event @ (EpollDispatch::ConsolePty | EpollDispatch::SerialPty) => { if let Some(ref vm) = self.vm { - vm.handle_pty().map_err(Error::Pty)?; + vm.handle_pty(event).map_err(Error::Pty)?; } } EpollDispatch::Api => { diff --git a/vmm/src/vm.rs b/vmm/src/vm.rs index 6f168943a..e7b963eab 100644 --- a/vmm/src/vm.rs +++ b/vmm/src/vm.rs @@ -17,7 +17,6 @@ use crate::config::{ ConsoleOutputMode, DeviceConfig, DiskConfig, FsConfig, HotplugMethod, NetConfig, PmemConfig, UserDeviceConfig, ValidationError, VmConfig, VsockConfig, }; -use crate::cpu; use crate::device_manager::{ self, get_win_size, Console, DeviceManager, DeviceManagerError, PtyPair, }; @@ -26,6 +25,7 @@ use crate::memory_manager::{Error as MemoryManagerError, MemoryManager}; use crate::migration::{get_vm_snapshot, url_to_path, VM_SNAPSHOT_FILE}; use crate::seccomp_filters::{get_seccomp_filter, Thread}; use crate::GuestMemoryMmap; +use crate::{cpu, EpollDispatch}; use crate::{ PciDeviceInfo, CPU_MANAGER_SNAPSHOT_ID, DEVICE_MANAGER_SNAPSHOT_ID, MEMORY_MANAGER_SNAPSHOT_ID, }; @@ -1911,28 +1911,32 @@ impl Vm { Ok(()) } - pub fn handle_pty(&self) -> Result<()> { + pub fn handle_pty(&self, event: EpollDispatch) -> Result<()> { // Could be a little dangerous, picks up a lock on device_manager // and goes into a blocking read. If the epoll loops starts to be // services by multiple threads likely need to revist this. let dm = self.device_manager.lock().unwrap(); - let mut out = [0u8; 64]; - if let Some(mut pty) = dm.serial_pty() { - let count = pty.main.read(&mut out).map_err(Error::PtyConsole)?; - let console = dm.console(); - if console.input_enabled() { - console - .queue_input_bytes_serial(&out[..count]) - .map_err(Error::Console)?; - } - }; - let count = match dm.console_pty() { - Some(mut pty) => pty.main.read(&mut out).map_err(Error::PtyConsole)?, - None => return Ok(()), - }; - let console = dm.console(); - if console.input_enabled() { - console.queue_input_bytes_console(&out[..count]) + + if matches!(event, EpollDispatch::SerialPty) { + if let Some(mut pty) = dm.serial_pty() { + let mut out = [0u8; 64]; + let count = pty.main.read(&mut out).map_err(Error::PtyConsole)?; + let console = dm.console(); + if console.input_enabled() { + console + .queue_input_bytes_serial(&out[..count]) + .map_err(Error::Console)?; + } + }; + } else if matches!(event, EpollDispatch::ConsolePty) { + if let Some(mut pty) = dm.console_pty() { + let mut out = [0u8; 64]; + let count = pty.main.read(&mut out).map_err(Error::PtyConsole)?; + let console = dm.console(); + if console.input_enabled() { + console.queue_input_bytes_console(&out[..count]) + } + }; } Ok(())