mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-10-01 02:55:45 +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:
parent
0d01eac1d4
commit
c2144b5690
@ -14,9 +14,9 @@ use libc::EFD_NONBLOCK;
|
|||||||
use seccompiler::{apply_filter, SeccompAction};
|
use seccompiler::{apply_filter, SeccompAction};
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::Write;
|
use std::io::{Read, Write};
|
||||||
use std::ops::DerefMut;
|
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
|
||||||
@ -40,6 +40,8 @@ const OUTPUT_QUEUE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 2;
|
|||||||
const INPUT_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 3;
|
const INPUT_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 3;
|
||||||
// Console configuration change event is triggered.
|
// Console configuration change event is triggered.
|
||||||
const CONFIG_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 4;
|
const CONFIG_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 4;
|
||||||
|
// File written to (input ready)
|
||||||
|
const FILE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 5;
|
||||||
|
|
||||||
//Console size feature bit
|
//Console size feature bit
|
||||||
const VIRTIO_CONSOLE_F_SIZE: u64 = 0;
|
const VIRTIO_CONSOLE_F_SIZE: u64 = 0;
|
||||||
@ -61,7 +63,7 @@ struct ConsoleEpollHandler {
|
|||||||
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
mem: GuestMemoryAtomic<GuestMemoryMmap>,
|
||||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||||
in_buffer: Arc<Mutex<VecDeque<u8>>>,
|
in_buffer: Arc<Mutex<VecDeque<u8>>>,
|
||||||
out: Arc<Mutex<Box<dyn io::Write + Send + Sync + 'static>>>,
|
endpoint: Endpoint,
|
||||||
input_queue_evt: EventFd,
|
input_queue_evt: EventFd,
|
||||||
output_queue_evt: EventFd,
|
output_queue_evt: EventFd,
|
||||||
input_evt: EventFd,
|
input_evt: EventFd,
|
||||||
@ -70,6 +72,42 @@ struct ConsoleEpollHandler {
|
|||||||
pause_evt: EventFd,
|
pause_evt: EventFd,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum Endpoint {
|
||||||
|
File(File),
|
||||||
|
FilePair(File, File),
|
||||||
|
Null,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Endpoint {
|
||||||
|
fn out_file(&self) -> Option<&File> {
|
||||||
|
match self {
|
||||||
|
Self::File(f) => Some(f),
|
||||||
|
Self::FilePair(f, _) => Some(f),
|
||||||
|
Self::Null => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn in_file(&self) -> Option<&File> {
|
||||||
|
match self {
|
||||||
|
Self::File(_) => None,
|
||||||
|
Self::FilePair(_, f) => Some(f),
|
||||||
|
Self::Null => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for Endpoint {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
match self {
|
||||||
|
Self::File(f) => Self::File(f.try_clone().unwrap()),
|
||||||
|
Self::FilePair(f_out, f_in) => {
|
||||||
|
Self::FilePair(f_out.try_clone().unwrap(), f_in.try_clone().unwrap())
|
||||||
|
}
|
||||||
|
Self::Null => Self::Null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ConsoleEpollHandler {
|
impl ConsoleEpollHandler {
|
||||||
/*
|
/*
|
||||||
* Each port of virtio console device has one receive
|
* Each port of virtio console device has one receive
|
||||||
@ -127,14 +165,10 @@ impl ConsoleEpollHandler {
|
|||||||
let mem = self.mem.memory();
|
let mem = self.mem.memory();
|
||||||
for avail_desc in trans_queue.iter(&mem) {
|
for avail_desc in trans_queue.iter(&mem) {
|
||||||
let len;
|
let len;
|
||||||
let mut out = self.out.lock().unwrap();
|
if let Some(ref mut out) = self.endpoint.out_file() {
|
||||||
let _ = mem.write_to(
|
let _ = mem.write_to(avail_desc.addr, out, avail_desc.len as usize);
|
||||||
avail_desc.addr,
|
let _ = out.flush();
|
||||||
&mut out.deref_mut(),
|
}
|
||||||
avail_desc.len as usize,
|
|
||||||
);
|
|
||||||
let _ = out.flush();
|
|
||||||
|
|
||||||
len = avail_desc.len;
|
len = avail_desc.len;
|
||||||
used_desc_heads[used_count] = (avail_desc.index, len);
|
used_desc_heads[used_count] = (avail_desc.index, len);
|
||||||
used_count += 1;
|
used_count += 1;
|
||||||
@ -165,6 +199,9 @@ impl ConsoleEpollHandler {
|
|||||||
helper.add_event(self.output_queue_evt.as_raw_fd(), OUTPUT_QUEUE_EVENT)?;
|
helper.add_event(self.output_queue_evt.as_raw_fd(), OUTPUT_QUEUE_EVENT)?;
|
||||||
helper.add_event(self.input_evt.as_raw_fd(), INPUT_EVENT)?;
|
helper.add_event(self.input_evt.as_raw_fd(), INPUT_EVENT)?;
|
||||||
helper.add_event(self.config_evt.as_raw_fd(), CONFIG_EVENT)?;
|
helper.add_event(self.config_evt.as_raw_fd(), CONFIG_EVENT)?;
|
||||||
|
if let Some(in_file) = self.endpoint.in_file() {
|
||||||
|
helper.add_event(in_file.as_raw_fd(), FILE_EVENT)?;
|
||||||
|
}
|
||||||
helper.run(paused, paused_sync, self)?;
|
helper.run(paused, paused_sync, self)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -217,6 +254,22 @@ impl EpollHelperHandler for ConsoleEpollHandler {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
FILE_EVENT => {
|
||||||
|
let mut input = [0u8; 64];
|
||||||
|
if let Some(ref mut in_file) = self.endpoint.in_file() {
|
||||||
|
if let Ok(count) = in_file.read(&mut input) {
|
||||||
|
let mut in_buffer = self.in_buffer.lock().unwrap();
|
||||||
|
in_buffer.extend(&input[..count]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.process_input_queue() {
|
||||||
|
if let Err(e) = self.signal_used_queue() {
|
||||||
|
error!("Failed to signal used queue: {:?}", e);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
error!("Unknown event for virtio-console");
|
error!("Unknown event for virtio-console");
|
||||||
return true;
|
return true;
|
||||||
@ -226,22 +279,14 @@ impl EpollHelperHandler for ConsoleEpollHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Input device.
|
/// Resize handler
|
||||||
pub struct ConsoleInput {
|
pub struct ConsoleResizer {
|
||||||
input_evt: EventFd,
|
|
||||||
config_evt: EventFd,
|
config_evt: EventFd,
|
||||||
in_buffer: Arc<Mutex<VecDeque<u8>>>,
|
|
||||||
config: Arc<Mutex<VirtioConsoleConfig>>,
|
config: Arc<Mutex<VirtioConsoleConfig>>,
|
||||||
acked_features: AtomicU64,
|
acked_features: AtomicU64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConsoleInput {
|
impl ConsoleResizer {
|
||||||
pub fn queue_input_bytes(&self, input: &[u8]) {
|
|
||||||
let mut in_buffer = self.in_buffer.lock().unwrap();
|
|
||||||
in_buffer.extend(input);
|
|
||||||
let _ = self.input_evt.write(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_console_size(&self, cols: u16, rows: u16) {
|
pub fn update_console_size(&self, cols: u16, rows: u16) {
|
||||||
if self
|
if self
|
||||||
.acked_features
|
.acked_features
|
||||||
@ -276,9 +321,10 @@ pub struct Console {
|
|||||||
common: VirtioCommon,
|
common: VirtioCommon,
|
||||||
id: String,
|
id: String,
|
||||||
config: Arc<Mutex<VirtioConsoleConfig>>,
|
config: Arc<Mutex<VirtioConsoleConfig>>,
|
||||||
input: Arc<ConsoleInput>,
|
resizer: Arc<ConsoleResizer>,
|
||||||
out: Arc<Mutex<Box<dyn io::Write + Send + Sync + 'static>>>,
|
endpoint: Endpoint,
|
||||||
seccomp_action: SeccompAction,
|
seccomp_action: SeccompAction,
|
||||||
|
in_buffer: Arc<Mutex<VecDeque<u8>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Versionize)]
|
#[derive(Versionize)]
|
||||||
@ -295,25 +341,22 @@ impl Console {
|
|||||||
/// Create a new virtio console device that gets random data from /dev/urandom.
|
/// Create a new virtio console device that gets random data from /dev/urandom.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
id: String,
|
id: String,
|
||||||
out: Box<dyn io::Write + Send + Sync + 'static>,
|
endpoint: Endpoint,
|
||||||
cols: u16,
|
cols: u16,
|
||||||
rows: u16,
|
rows: u16,
|
||||||
iommu: bool,
|
iommu: bool,
|
||||||
seccomp_action: SeccompAction,
|
seccomp_action: SeccompAction,
|
||||||
) -> io::Result<(Console, Arc<ConsoleInput>)> {
|
) -> io::Result<(Console, Arc<ConsoleResizer>)> {
|
||||||
let mut avail_features = 1u64 << VIRTIO_F_VERSION_1 | 1u64 << VIRTIO_CONSOLE_F_SIZE;
|
let mut avail_features = 1u64 << VIRTIO_F_VERSION_1 | 1u64 << VIRTIO_CONSOLE_F_SIZE;
|
||||||
|
|
||||||
if iommu {
|
if iommu {
|
||||||
avail_features |= 1u64 << VIRTIO_F_IOMMU_PLATFORM;
|
avail_features |= 1u64 << VIRTIO_F_IOMMU_PLATFORM;
|
||||||
}
|
}
|
||||||
|
|
||||||
let input_evt = EventFd::new(EFD_NONBLOCK).unwrap();
|
|
||||||
let config_evt = EventFd::new(EFD_NONBLOCK).unwrap();
|
let config_evt = EventFd::new(EFD_NONBLOCK).unwrap();
|
||||||
let console_config = Arc::new(Mutex::new(VirtioConsoleConfig::new(cols, rows)));
|
let console_config = Arc::new(Mutex::new(VirtioConsoleConfig::new(cols, rows)));
|
||||||
let console_input = Arc::new(ConsoleInput {
|
let resizer = Arc::new(ConsoleResizer {
|
||||||
input_evt,
|
|
||||||
config_evt,
|
config_evt,
|
||||||
in_buffer: Arc::new(Mutex::new(VecDeque::new())),
|
|
||||||
config: console_config.clone(),
|
config: console_config.clone(),
|
||||||
acked_features: AtomicU64::new(0),
|
acked_features: AtomicU64::new(0),
|
||||||
});
|
});
|
||||||
@ -330,11 +373,12 @@ impl Console {
|
|||||||
},
|
},
|
||||||
id,
|
id,
|
||||||
config: console_config,
|
config: console_config,
|
||||||
input: console_input.clone(),
|
resizer: resizer.clone(),
|
||||||
out: Arc::new(Mutex::new(out)),
|
endpoint,
|
||||||
seccomp_action,
|
seccomp_action,
|
||||||
|
in_buffer: Arc::new(Mutex::new(VecDeque::new())),
|
||||||
},
|
},
|
||||||
console_input,
|
resizer,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -343,7 +387,7 @@ impl Console {
|
|||||||
avail_features: self.common.avail_features,
|
avail_features: self.common.avail_features,
|
||||||
acked_features: self.common.acked_features,
|
acked_features: self.common.acked_features,
|
||||||
config: *(self.config.lock().unwrap()),
|
config: *(self.config.lock().unwrap()),
|
||||||
in_buffer: self.input.in_buffer.lock().unwrap().clone().into(),
|
in_buffer: self.in_buffer.lock().unwrap().clone().into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,7 +395,7 @@ impl Console {
|
|||||||
self.common.avail_features = state.avail_features;
|
self.common.avail_features = state.avail_features;
|
||||||
self.common.acked_features = state.acked_features;
|
self.common.acked_features = state.acked_features;
|
||||||
*(self.config.lock().unwrap()) = state.config;
|
*(self.config.lock().unwrap()) = state.config;
|
||||||
*(self.input.in_buffer.lock().unwrap()) = state.in_buffer.clone().into();
|
*(self.in_buffer.lock().unwrap()) = state.in_buffer.clone().into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,7 +437,7 @@ impl VirtioDevice for Console {
|
|||||||
mut queue_evts: Vec<EventFd>,
|
mut queue_evts: Vec<EventFd>,
|
||||||
) -> ActivateResult {
|
) -> ActivateResult {
|
||||||
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
self.common.activate(&queues, &queue_evts, &interrupt_cb)?;
|
||||||
self.input
|
self.resizer
|
||||||
.acked_features
|
.acked_features
|
||||||
.store(self.common.acked_features, Ordering::Relaxed);
|
.store(self.common.acked_features, Ordering::Relaxed);
|
||||||
|
|
||||||
@ -404,17 +448,18 @@ impl VirtioDevice for Console {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let (kill_evt, pause_evt) = self.common.dup_eventfds();
|
let (kill_evt, pause_evt) = self.common.dup_eventfds();
|
||||||
|
let input_evt = EventFd::new(EFD_NONBLOCK).unwrap();
|
||||||
|
|
||||||
let mut handler = ConsoleEpollHandler {
|
let mut handler = ConsoleEpollHandler {
|
||||||
queues,
|
queues,
|
||||||
mem,
|
mem,
|
||||||
interrupt_cb,
|
interrupt_cb,
|
||||||
in_buffer: self.input.in_buffer.clone(),
|
in_buffer: self.in_buffer.clone(),
|
||||||
out: self.out.clone(),
|
endpoint: self.endpoint.clone(),
|
||||||
input_queue_evt: queue_evts.remove(0),
|
input_queue_evt: queue_evts.remove(0),
|
||||||
output_queue_evt: queue_evts.remove(0),
|
output_queue_evt: queue_evts.remove(0),
|
||||||
input_evt: self.input.input_evt.try_clone().unwrap(),
|
input_evt,
|
||||||
config_evt: self.input.config_evt.try_clone().unwrap(),
|
config_evt: self.resizer.config_evt.try_clone().unwrap(),
|
||||||
kill_evt,
|
kill_evt,
|
||||||
pause_evt,
|
pause_evt,
|
||||||
};
|
};
|
||||||
|
@ -73,7 +73,7 @@ use seccompiler::SeccompAction;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::fs::{read_link, File, OpenOptions};
|
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::mem::zeroed;
|
||||||
use std::num::Wrapping;
|
use std::num::Wrapping;
|
||||||
use std::os::unix::fs::OpenOptionsExt;
|
use std::os::unix::fs::OpenOptionsExt;
|
||||||
@ -88,7 +88,7 @@ use vfio_ioctls::{VfioContainer, VfioDevice};
|
|||||||
use virtio_devices::transport::VirtioPciDevice;
|
use virtio_devices::transport::VirtioPciDevice;
|
||||||
use virtio_devices::transport::VirtioTransport;
|
use virtio_devices::transport::VirtioTransport;
|
||||||
use virtio_devices::vhost_user::VhostUserConfig;
|
use virtio_devices::vhost_user::VhostUserConfig;
|
||||||
use virtio_devices::{DmaRemapping, IommuMapping};
|
use virtio_devices::{DmaRemapping, Endpoint, IommuMapping};
|
||||||
use virtio_devices::{VirtioSharedMemory, VirtioSharedMemoryList};
|
use virtio_devices::{VirtioSharedMemory, VirtioSharedMemoryList};
|
||||||
use vm_allocator::SystemAllocator;
|
use vm_allocator::SystemAllocator;
|
||||||
#[cfg(feature = "kvm")]
|
#[cfg(feature = "kvm")]
|
||||||
@ -535,7 +535,7 @@ pub struct Console {
|
|||||||
serial: Option<Arc<Mutex<Serial>>>,
|
serial: Option<Arc<Mutex<Serial>>>,
|
||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
serial: Option<Arc<Mutex<Pl011>>>,
|
serial: Option<Arc<Mutex<Pl011>>>,
|
||||||
virtio_console_input: Option<Arc<virtio_devices::ConsoleInput>>,
|
console_resizer: Option<Arc<virtio_devices::ConsoleResizer>>,
|
||||||
input: Option<ConsoleInput>,
|
input: Option<ConsoleInput>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -552,21 +552,9 @@ impl Console {
|
|||||||
Ok(())
|
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) {
|
pub fn update_console_size(&self, cols: u16, rows: u16) {
|
||||||
if self.virtio_console_input.is_some() {
|
if let Some(resizer) = self.console_resizer.as_ref() {
|
||||||
self.virtio_console_input
|
resizer.update_console_size(cols, rows)
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.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))
|
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(
|
fn add_console_device(
|
||||||
&mut self,
|
&mut self,
|
||||||
interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = LegacyIrqGroupConfig>>,
|
interrupt_manager: &Arc<dyn InterruptManager<GroupConfig = LegacyIrqGroupConfig>>,
|
||||||
@ -1702,6 +1765,7 @@ impl DeviceManager {
|
|||||||
serial_pty: Option<PtyPair>,
|
serial_pty: Option<PtyPair>,
|
||||||
console_pty: Option<PtyPair>,
|
console_pty: Option<PtyPair>,
|
||||||
) -> DeviceManagerResult<Arc<Console>> {
|
) -> DeviceManagerResult<Arc<Console>> {
|
||||||
|
let console_config = self.config.lock().unwrap().console.clone();
|
||||||
let serial_config = self.config.lock().unwrap().serial.clone();
|
let serial_config = self.config.lock().unwrap().serial.clone();
|
||||||
let serial_writer: Option<Box<dyn io::Write + Send>> = match serial_config.mode {
|
let serial_writer: Option<Box<dyn io::Write + Send>> = match serial_config.mode {
|
||||||
ConsoleOutputMode::File => Some(Box::new(
|
ConsoleOutputMode::File => Some(Box::new(
|
||||||
@ -1736,66 +1800,7 @@ impl DeviceManager {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create serial and virtio-console
|
let console_resizer = self.add_virtio_console_device(virtio_devices, console_pty)?;
|
||||||
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 input = if serial_config.mode.input_enabled() {
|
let input = if serial_config.mode.input_enabled() {
|
||||||
Some(ConsoleInput::Serial)
|
Some(ConsoleInput::Serial)
|
||||||
@ -1807,8 +1812,8 @@ impl DeviceManager {
|
|||||||
|
|
||||||
Ok(Arc::new(Console {
|
Ok(Arc::new(Console {
|
||||||
serial,
|
serial,
|
||||||
virtio_console_input,
|
|
||||||
input,
|
input,
|
||||||
|
console_resizer,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,8 +150,7 @@ pub enum EpollDispatch {
|
|||||||
Stdin = 2,
|
Stdin = 2,
|
||||||
Api = 3,
|
Api = 3,
|
||||||
ActivateVirtioDevices = 4,
|
ActivateVirtioDevices = 4,
|
||||||
ConsolePty = 5,
|
SerialPty = 5,
|
||||||
SerialPty = 6,
|
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,8 +163,7 @@ impl From<u64> for EpollDispatch {
|
|||||||
2 => Stdin,
|
2 => Stdin,
|
||||||
3 => Api,
|
3 => Api,
|
||||||
4 => ActivateVirtioDevices,
|
4 => ActivateVirtioDevices,
|
||||||
5 => ConsolePty,
|
5 => SerialPty,
|
||||||
6 => SerialPty,
|
|
||||||
_ => Unknown,
|
_ => Unknown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -324,10 +322,6 @@ impl Vmm {
|
|||||||
let reset_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
|
let reset_evt = EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?;
|
||||||
let activate_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
|
epoll
|
||||||
.add_event(&exit_evt, EpollDispatch::Exit)
|
.add_event(&exit_evt, EpollDispatch::Exit)
|
||||||
.map_err(Error::Epoll)?;
|
.map_err(Error::Epoll)?;
|
||||||
@ -400,11 +394,14 @@ impl Vmm {
|
|||||||
.add_event(&serial_pty.main, EpollDispatch::SerialPty)
|
.add_event(&serial_pty.main, EpollDispatch::SerialPty)
|
||||||
.map_err(VmError::EventfdError)?;
|
.map_err(VmError::EventfdError)?;
|
||||||
};
|
};
|
||||||
if let Some(console_pty) = vm.console_pty() {
|
if matches!(
|
||||||
self.epoll
|
vm_config.lock().unwrap().serial.mode,
|
||||||
.add_event(&console_pty.main, EpollDispatch::ConsolePty)
|
config::ConsoleOutputMode::Tty
|
||||||
.map_err(VmError::EventfdError)?;
|
) && unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0
|
||||||
};
|
{
|
||||||
|
self.epoll.add_stdin().map_err(VmError::EventfdError)?;
|
||||||
|
}
|
||||||
|
|
||||||
self.vm = Some(vm);
|
self.vm = Some(vm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1302,7 +1299,7 @@ impl Vmm {
|
|||||||
.map_err(Error::ActivateVirtioDevices)?;
|
.map_err(Error::ActivateVirtioDevices)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
event @ (EpollDispatch::ConsolePty | EpollDispatch::SerialPty) => {
|
event @ EpollDispatch::SerialPty => {
|
||||||
if let Some(ref vm) = self.vm {
|
if let Some(ref vm) = self.vm {
|
||||||
vm.handle_pty(event).map_err(Error::Pty)?;
|
vm.handle_pty(event).map_err(Error::Pty)?;
|
||||||
}
|
}
|
||||||
|
@ -1928,15 +1928,6 @@ impl Vm {
|
|||||||
.map_err(Error::Console)?;
|
.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(())
|
Ok(())
|
||||||
@ -1964,15 +1955,6 @@ impl Vm {
|
|||||||
.console()
|
.console()
|
||||||
.queue_input_bytes_serial(&out[..count])
|
.queue_input_bytes_serial(&out[..count])
|
||||||
.map_err(Error::Console)?;
|
.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(())
|
Ok(())
|
||||||
|
Loading…
Reference in New Issue
Block a user