mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-11-04 19:11:11 +00:00
vmm: Add new "null" serial/console output mode
Poor performance was observed when booting kernels with "console=ttyS0" and the serial port disabled. This change introduces a "null" console output mode and makes it the default for the serial console. In this case the serial port is advertised as per other output modes but there is no input and any output is dropped. Fixes: #163 Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
parent
f910476dd7
commit
d9a355f85a
@ -67,7 +67,7 @@ pub struct Serial {
|
||||
}
|
||||
|
||||
impl Serial {
|
||||
fn new(interrupt: Box<Interrupt>, out: Option<Box<io::Write + Send>>) -> Serial {
|
||||
pub fn new(interrupt: Box<Interrupt>, out: Option<Box<io::Write + Send>>) -> Serial {
|
||||
Serial {
|
||||
interrupt_enable: 0,
|
||||
interrupt_identification: DEFAULT_INTERRUPT_IDENTIFICATION,
|
||||
|
126
src/main.rs
126
src/main.rs
@ -137,13 +137,13 @@ fn main() {
|
||||
.arg(
|
||||
Arg::with_name("serial")
|
||||
.long("serial")
|
||||
.help("Control serial port: off|tty|file=/path/to/a/file")
|
||||
.default_value("off"),
|
||||
.help("Control serial port: off|null|tty|file=/path/to/a/file")
|
||||
.default_value("null"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("console")
|
||||
.long("console")
|
||||
.help("Control (virtio) console: off|tty|file=/path/to/a/file")
|
||||
.help("Control (virtio) console: off|null|tty|file=/path/to/a/file")
|
||||
.default_value("tty"),
|
||||
)
|
||||
.arg(
|
||||
@ -1322,7 +1322,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serial_disable() {
|
||||
fn test_serial_off() {
|
||||
test_block!(tb, "", {
|
||||
let mut clear = ClearDiskConfig::new();
|
||||
let guest = Guest::new(&mut clear);
|
||||
@ -1380,6 +1380,124 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serial_null() {
|
||||
test_block!(tb, "", {
|
||||
let mut clear = ClearDiskConfig::new();
|
||||
let guest = Guest::new(&mut clear);
|
||||
let mut child = Command::new("target/debug/cloud-hypervisor")
|
||||
.args(&["--cpus", "1"])
|
||||
.args(&["--memory", "size=512M"])
|
||||
.args(&["--kernel", guest.fw_path.as_str()])
|
||||
.args(&[
|
||||
"--disk",
|
||||
guest
|
||||
.disk_config
|
||||
.disk(DiskType::OperatingSystem)
|
||||
.unwrap()
|
||||
.as_str(),
|
||||
guest
|
||||
.disk_config
|
||||
.disk(DiskType::CloudInit)
|
||||
.unwrap()
|
||||
.as_str(),
|
||||
])
|
||||
.args(&["--net", guest.default_net_string().as_str()])
|
||||
.args(&["--serial", "null"])
|
||||
.args(&["--console", "off"])
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(20, 0));
|
||||
|
||||
// Test that there is a ttyS0
|
||||
aver_eq!(
|
||||
tb,
|
||||
guest
|
||||
.ssh_command("cat /proc/interrupts | grep 'IO-APIC' | grep -c 'ttyS0'")
|
||||
.trim()
|
||||
.parse::<u32>()
|
||||
.unwrap(),
|
||||
1
|
||||
);
|
||||
|
||||
guest.ssh_command("sudo reboot");
|
||||
thread::sleep(std::time::Duration::new(10, 0));
|
||||
let _ = child.kill();
|
||||
match child.wait_with_output() {
|
||||
Ok(out) => {
|
||||
aver!(
|
||||
tb,
|
||||
!String::from_utf8_lossy(&out.stdout).contains("cloud login:")
|
||||
);
|
||||
}
|
||||
Err(_) => aver!(tb, false),
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serial_tty() {
|
||||
test_block!(tb, "", {
|
||||
let mut clear = ClearDiskConfig::new();
|
||||
let guest = Guest::new(&mut clear);
|
||||
let mut child = Command::new("target/debug/cloud-hypervisor")
|
||||
.args(&["--cpus", "1"])
|
||||
.args(&["--memory", "size=512M"])
|
||||
.args(&["--kernel", guest.fw_path.as_str()])
|
||||
.args(&[
|
||||
"--disk",
|
||||
guest
|
||||
.disk_config
|
||||
.disk(DiskType::OperatingSystem)
|
||||
.unwrap()
|
||||
.as_str(),
|
||||
guest
|
||||
.disk_config
|
||||
.disk(DiskType::CloudInit)
|
||||
.unwrap()
|
||||
.as_str(),
|
||||
])
|
||||
.args(&["--net", guest.default_net_string().as_str()])
|
||||
.args(&["--serial", "tty"])
|
||||
.args(&["--console", "off"])
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
thread::sleep(std::time::Duration::new(20, 0));
|
||||
|
||||
// Test that there is a ttyS0
|
||||
aver_eq!(
|
||||
tb,
|
||||
guest
|
||||
.ssh_command("cat /proc/interrupts | grep 'IO-APIC' | grep -c 'ttyS0'")
|
||||
.trim()
|
||||
.parse::<u32>()
|
||||
.unwrap(),
|
||||
1
|
||||
);
|
||||
|
||||
guest.ssh_command("sudo reboot");
|
||||
thread::sleep(std::time::Duration::new(10, 0));
|
||||
let _ = child.kill();
|
||||
match child.wait_with_output() {
|
||||
Ok(out) => {
|
||||
aver!(
|
||||
tb,
|
||||
String::from_utf8_lossy(&out.stdout).contains("cloud login:")
|
||||
);
|
||||
}
|
||||
Err(_) => aver!(tb, false),
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serial_file() {
|
||||
test_block!(tb, "", {
|
||||
|
@ -350,6 +350,7 @@ pub enum ConsoleOutputMode {
|
||||
Off,
|
||||
Tty,
|
||||
File,
|
||||
Null,
|
||||
}
|
||||
|
||||
impl ConsoleOutputMode {
|
||||
@ -383,6 +384,11 @@ impl<'a> ConsoleConfig<'a> {
|
||||
mode: ConsoleOutputMode::File,
|
||||
file: Some(Path::new(¶m[5..])),
|
||||
})
|
||||
} else if param.starts_with("null") {
|
||||
Ok(Self {
|
||||
mode: ConsoleOutputMode::Null,
|
||||
file: None,
|
||||
})
|
||||
} else {
|
||||
Err(Error::ParseConsoleParam)
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ use pci::{
|
||||
use qcow::{self, ImageType, QcowFile};
|
||||
use std::ffi::CString;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{self, stdout};
|
||||
use std::io::{self, sink, stdout};
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
use std::ptr::null_mut;
|
||||
@ -561,9 +561,9 @@ impl DeviceManager {
|
||||
.map_err(DeviceManagerError::SerialOutputFileOpen)?,
|
||||
)),
|
||||
ConsoleOutputMode::Tty => Some(Box::new(stdout())),
|
||||
ConsoleOutputMode::Off => None,
|
||||
ConsoleOutputMode::Off | ConsoleOutputMode::Null => None,
|
||||
};
|
||||
let serial = if serial_writer.is_some() {
|
||||
let serial = if vm_info.vm_cfg.serial.mode != ConsoleOutputMode::Off {
|
||||
// Serial is tied to IRQ #4
|
||||
let serial_irq = 4;
|
||||
let interrupt: Box<devices::Interrupt> = if let Some(ioapic) = &ioapic {
|
||||
@ -578,9 +578,9 @@ impl DeviceManager {
|
||||
Box::new(KernelIoapicIrq::new(serial_evt))
|
||||
};
|
||||
|
||||
Some(Arc::new(Mutex::new(devices::legacy::Serial::new_out(
|
||||
Some(Arc::new(Mutex::new(devices::legacy::Serial::new(
|
||||
interrupt,
|
||||
serial_writer.unwrap(),
|
||||
serial_writer,
|
||||
))))
|
||||
} else {
|
||||
None
|
||||
@ -601,6 +601,7 @@ impl DeviceManager {
|
||||
.map_err(DeviceManagerError::ConsoleOutputFileOpen)?,
|
||||
)),
|
||||
ConsoleOutputMode::Tty => Some(Box::new(stdout())),
|
||||
ConsoleOutputMode::Null => Some(Box::new(sink())),
|
||||
ConsoleOutputMode::Off => None,
|
||||
};
|
||||
let console = if console_writer.is_some() {
|
||||
|
Loading…
Reference in New Issue
Block a user