mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm, virtio-console: Move input reading into virtio-console thread
Move the processing of the input from stdin, PTY or file from the VMM thread to the existing virtio-console thread. The handling of the resize of a virtio-console has not changed but the name of the struct used to support that has been renamed to reflect its usage. Fixes: #3060 Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
+83
-78
@@ -73,7 +73,7 @@ use seccompiler::SeccompAction;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::fs::{read_link, File, OpenOptions};
|
||||
use std::io::{self, sink, stdout, Seek, SeekFrom};
|
||||
use std::io::{self, stdout, Seek, SeekFrom};
|
||||
use std::mem::zeroed;
|
||||
use std::num::Wrapping;
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
@@ -88,7 +88,7 @@ use vfio_ioctls::{VfioContainer, VfioDevice};
|
||||
use virtio_devices::transport::VirtioPciDevice;
|
||||
use virtio_devices::transport::VirtioTransport;
|
||||
use virtio_devices::vhost_user::VhostUserConfig;
|
||||
use virtio_devices::{DmaRemapping, IommuMapping};
|
||||
use virtio_devices::{DmaRemapping, Endpoint, IommuMapping};
|
||||
use virtio_devices::{VirtioSharedMemory, VirtioSharedMemoryList};
|
||||
use vm_allocator::SystemAllocator;
|
||||
#[cfg(feature = "kvm")]
|
||||
@@ -535,7 +535,7 @@ pub struct Console {
|
||||
serial: Option<Arc<Mutex<Serial>>>,
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
serial: Option<Arc<Mutex<Pl011>>>,
|
||||
virtio_console_input: Option<Arc<virtio_devices::ConsoleInput>>,
|
||||
console_resizer: Option<Arc<virtio_devices::ConsoleResizer>>,
|
||||
input: Option<ConsoleInput>,
|
||||
}
|
||||
|
||||
@@ -552,21 +552,9 @@ impl Console {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn queue_input_bytes_console(&self, out: &[u8]) {
|
||||
if self.virtio_console_input.is_some() {
|
||||
self.virtio_console_input
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.queue_input_bytes(out);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_console_size(&self, cols: u16, rows: u16) {
|
||||
if self.virtio_console_input.is_some() {
|
||||
self.virtio_console_input
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.update_console_size(cols, rows)
|
||||
if let Some(resizer) = self.console_resizer.as_ref() {
|
||||
resizer.update_console_size(cols, rows)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1695,6 +1683,81 @@ impl DeviceManager {
|
||||
self.modify_mode(f.as_raw_fd(), |t| t.c_lflag &= !(ICANON | ECHO | ISIG))
|
||||
}
|
||||
|
||||
fn add_virtio_console_device(
|
||||
&mut self,
|
||||
virtio_devices: &mut Vec<(VirtioDeviceArc, bool, String)>,
|
||||
console_pty: Option<PtyPair>,
|
||||
) -> DeviceManagerResult<Option<Arc<virtio_devices::ConsoleResizer>>> {
|
||||
let console_config = self.config.lock().unwrap().console.clone();
|
||||
let endpoint = match console_config.mode {
|
||||
ConsoleOutputMode::File => {
|
||||
let file = File::create(console_config.file.as_ref().unwrap())
|
||||
.map_err(DeviceManagerError::ConsoleOutputFileOpen)?;
|
||||
Endpoint::File(file)
|
||||
}
|
||||
ConsoleOutputMode::Pty => {
|
||||
if let Some(pty) = console_pty {
|
||||
self.config.lock().unwrap().console.file = Some(pty.path.clone());
|
||||
let file = pty.main.try_clone().unwrap();
|
||||
self.console_pty = Some(Arc::new(Mutex::new(pty)));
|
||||
Endpoint::FilePair(file.try_clone().unwrap(), file)
|
||||
} else {
|
||||
let (main, mut sub, path) =
|
||||
create_pty(false).map_err(DeviceManagerError::ConsolePtyOpen)?;
|
||||
self.set_raw_mode(&mut sub)
|
||||
.map_err(DeviceManagerError::SetPtyRaw)?;
|
||||
self.config.lock().unwrap().console.file = Some(path.clone());
|
||||
let file = main.try_clone().unwrap();
|
||||
self.console_pty = Some(Arc::new(Mutex::new(PtyPair { main, sub, path })));
|
||||
Endpoint::FilePair(file.try_clone().unwrap(), file)
|
||||
}
|
||||
}
|
||||
ConsoleOutputMode::Tty => {
|
||||
// If an interactive TTY then we can accept input
|
||||
if unsafe { libc::isatty(libc::STDIN_FILENO) == 1 } {
|
||||
Endpoint::FilePair(
|
||||
// Duplicating the file descriptors like this is needed as otherwise
|
||||
// they will be closed on a reboot and the numbers reused
|
||||
unsafe { File::from_raw_fd(libc::dup(libc::STDOUT_FILENO)) },
|
||||
unsafe { File::from_raw_fd(libc::dup(libc::STDIN_FILENO)) },
|
||||
)
|
||||
} else {
|
||||
Endpoint::File(unsafe { File::from_raw_fd(libc::dup(libc::STDOUT_FILENO)) })
|
||||
}
|
||||
}
|
||||
ConsoleOutputMode::Null => Endpoint::Null,
|
||||
ConsoleOutputMode::Off => return Ok(None),
|
||||
};
|
||||
let (col, row) = get_win_size();
|
||||
let id = String::from(CONSOLE_DEVICE_NAME);
|
||||
|
||||
let (virtio_console_device, console_resizer) = virtio_devices::Console::new(
|
||||
id.clone(),
|
||||
endpoint,
|
||||
col,
|
||||
row,
|
||||
self.force_iommu | console_config.iommu,
|
||||
self.seccomp_action.clone(),
|
||||
)
|
||||
.map_err(DeviceManagerError::CreateVirtioConsole)?;
|
||||
let virtio_console_device = Arc::new(Mutex::new(virtio_console_device));
|
||||
virtio_devices.push((
|
||||
Arc::clone(&virtio_console_device) as VirtioDeviceArc,
|
||||
console_config.iommu,
|
||||
id.clone(),
|
||||
));
|
||||
|
||||
// Fill the device tree with a new node. In case of restore, we
|
||||
// know there is nothing to do, so we can simply override the
|
||||
// existing entry.
|
||||
self.device_tree
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(id.clone(), device_node!(id, virtio_console_device));
|
||||
|
||||
Ok(Some(console_resizer))
|
||||
}
|
||||
|
||||
fn add_console_device(
|
||||
&mut self,
|
||||
interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = LegacyIrqGroupConfig>>,
|
||||
@@ -1702,6 +1765,7 @@ impl DeviceManager {
|
||||
serial_pty: Option<PtyPair>,
|
||||
console_pty: Option<PtyPair>,
|
||||
) -> DeviceManagerResult<Arc<Console>> {
|
||||
let console_config = self.config.lock().unwrap().console.clone();
|
||||
let serial_config = self.config.lock().unwrap().serial.clone();
|
||||
let serial_writer: Option<Box<dyn io::Write + Send>> = match serial_config.mode {
|
||||
ConsoleOutputMode::File => Some(Box::new(
|
||||
@@ -1736,66 +1800,7 @@ impl DeviceManager {
|
||||
None
|
||||
};
|
||||
|
||||
// Create serial and virtio-console
|
||||
let console_config = self.config.lock().unwrap().console.clone();
|
||||
let console_writer: Option<Box<dyn io::Write + Send + Sync>> = match console_config.mode {
|
||||
ConsoleOutputMode::File => Some(Box::new(
|
||||
File::create(console_config.file.as_ref().unwrap())
|
||||
.map_err(DeviceManagerError::ConsoleOutputFileOpen)?,
|
||||
)),
|
||||
ConsoleOutputMode::Pty => {
|
||||
if let Some(pty) = console_pty {
|
||||
self.config.lock().unwrap().console.file = Some(pty.path.clone());
|
||||
let writer = pty.main.try_clone().unwrap();
|
||||
self.console_pty = Some(Arc::new(Mutex::new(pty)));
|
||||
Some(Box::new(writer))
|
||||
} else {
|
||||
let (main, mut sub, path) =
|
||||
create_pty(false).map_err(DeviceManagerError::ConsolePtyOpen)?;
|
||||
self.set_raw_mode(&mut sub)
|
||||
.map_err(DeviceManagerError::SetPtyRaw)?;
|
||||
self.config.lock().unwrap().console.file = Some(path.clone());
|
||||
let writer = main.try_clone().unwrap();
|
||||
self.console_pty = Some(Arc::new(Mutex::new(PtyPair { main, sub, path })));
|
||||
Some(Box::new(writer))
|
||||
}
|
||||
}
|
||||
ConsoleOutputMode::Tty => Some(Box::new(stdout())),
|
||||
ConsoleOutputMode::Null => Some(Box::new(sink())),
|
||||
ConsoleOutputMode::Off => None,
|
||||
};
|
||||
let (col, row) = get_win_size();
|
||||
let virtio_console_input = if let Some(writer) = console_writer {
|
||||
let id = String::from(CONSOLE_DEVICE_NAME);
|
||||
|
||||
let (virtio_console_device, virtio_console_input) = virtio_devices::Console::new(
|
||||
id.clone(),
|
||||
writer,
|
||||
col,
|
||||
row,
|
||||
self.force_iommu | console_config.iommu,
|
||||
self.seccomp_action.clone(),
|
||||
)
|
||||
.map_err(DeviceManagerError::CreateVirtioConsole)?;
|
||||
let virtio_console_device = Arc::new(Mutex::new(virtio_console_device));
|
||||
virtio_devices.push((
|
||||
Arc::clone(&virtio_console_device) as VirtioDeviceArc,
|
||||
console_config.iommu,
|
||||
id.clone(),
|
||||
));
|
||||
|
||||
// Fill the device tree with a new node. In case of restore, we
|
||||
// know there is nothing to do, so we can simply override the
|
||||
// existing entry.
|
||||
self.device_tree
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(id.clone(), device_node!(id, virtio_console_device));
|
||||
|
||||
Some(virtio_console_input)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let console_resizer = self.add_virtio_console_device(virtio_devices, console_pty)?;
|
||||
|
||||
let input = if serial_config.mode.input_enabled() {
|
||||
Some(ConsoleInput::Serial)
|
||||
@@ -1807,8 +1812,8 @@ impl DeviceManager {
|
||||
|
||||
Ok(Arc::new(Console {
|
||||
serial,
|
||||
virtio_console_input,
|
||||
input,
|
||||
console_resizer,
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
+11
-14
@@ -150,8 +150,7 @@ pub enum EpollDispatch {
|
||||
Stdin = 2,
|
||||
Api = 3,
|
||||
ActivateVirtioDevices = 4,
|
||||
ConsolePty = 5,
|
||||
SerialPty = 6,
|
||||
SerialPty = 5,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
@@ -164,8 +163,7 @@ impl From<u64> for EpollDispatch {
|
||||
2 => Stdin,
|
||||
3 => Api,
|
||||
4 => ActivateVirtioDevices,
|
||||
5 => ConsolePty,
|
||||
6 => SerialPty,
|
||||
5 => SerialPty,
|
||||
_ => Unknown,
|
||||
}
|
||||
}
|
||||
@@ -324,10 +322,6 @@ impl Vmm {
|
||||
let reset_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
|
||||
let activate_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
|
||||
|
||||
if unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0 {
|
||||
epoll.add_stdin().map_err(Error::Epoll)?;
|
||||
}
|
||||
|
||||
epoll
|
||||
.add_event(&exit_evt, EpollDispatch::Exit)
|
||||
.map_err(Error::Epoll)?;
|
||||
@@ -400,11 +394,14 @@ impl Vmm {
|
||||
.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::ConsolePty)
|
||||
.map_err(VmError::EventfdError)?;
|
||||
};
|
||||
if matches!(
|
||||
vm_config.lock().unwrap().serial.mode,
|
||||
config::ConsoleOutputMode::Tty
|
||||
) && unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0
|
||||
{
|
||||
self.epoll.add_stdin().map_err(VmError::EventfdError)?;
|
||||
}
|
||||
|
||||
self.vm = Some(vm);
|
||||
}
|
||||
}
|
||||
@@ -1302,7 +1299,7 @@ impl Vmm {
|
||||
.map_err(Error::ActivateVirtioDevices)?;
|
||||
}
|
||||
}
|
||||
event @ (EpollDispatch::ConsolePty | EpollDispatch::SerialPty) => {
|
||||
event @ EpollDispatch::SerialPty => {
|
||||
if let Some(ref vm) = self.vm {
|
||||
vm.handle_pty(event).map_err(Error::Pty)?;
|
||||
}
|
||||
|
||||
@@ -1928,15 +1928,6 @@ impl Vm {
|
||||
.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(())
|
||||
@@ -1964,15 +1955,6 @@ impl Vm {
|
||||
.console()
|
||||
.queue_input_bytes_serial(&out[..count])
|
||||
.map_err(Error::Console)?;
|
||||
} else if matches!(
|
||||
self.config.lock().unwrap().console.mode,
|
||||
ConsoleOutputMode::Tty
|
||||
) {
|
||||
self.device_manager
|
||||
.lock()
|
||||
.unwrap()
|
||||
.console()
|
||||
.queue_input_bytes_console(&out[..count])
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user