mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-02-22 03:12:27 +00:00
vmm: device_manager: Update virtio-console for proper PTY support
Given the virtio-console is now able to buffer its output when no PTY is connected on the other end, the device manager code is updated to enable this. Moving the endpoint type from FilePair to PtyPair enables the proper codepath in the virtio-console implementation, as well as updating the PTY resize code, and forcing the PTY to always be non-blocking. The non-blocking behavior is required to avoid blocking the guest that would be waiting on the virtio-console driver. When receiving an EWOULDBLOCK error, the output will simply be redirected to the temporary buffer so that it can be later flushed. The PTY resize logic has been slightly modified to ensure the PTY file descriptors are closed. It avoids the child process to keep a hold onto the PTY device, which would have caused the PTY to believe something is connected on the other end, which would have prevented the detection of any new connection on the PTY. Fixes #4521 Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
parent
a391bce781
commit
8c02648ac9
@ -483,7 +483,7 @@ const DEVICE_MANAGER_ACPI_SIZE: usize = 0x10;
|
||||
const TIOCSPTLCK: libc::c_int = 0x4004_5431;
|
||||
const TIOCGTPEER: libc::c_int = 0x5441;
|
||||
|
||||
pub fn create_pty(non_blocking: bool) -> io::Result<(File, File, PathBuf)> {
|
||||
pub fn create_pty() -> io::Result<(File, File, PathBuf)> {
|
||||
// Try to use /dev/pts/ptmx first then fall back to /dev/ptmx
|
||||
// This is done to try and use the devpts filesystem that
|
||||
// could be available for use in the process's namespace first.
|
||||
@ -492,7 +492,7 @@ pub fn create_pty(non_blocking: bool) -> io::Result<(File, File, PathBuf)> {
|
||||
// See https://www.kernel.org/doc/Documentation/filesystems/devpts.txt
|
||||
// for further details.
|
||||
|
||||
let custom_flags = libc::O_NOCTTY | if non_blocking { libc::O_NONBLOCK } else { 0 };
|
||||
let custom_flags = libc::O_NONBLOCK;
|
||||
let main = match OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
@ -1864,7 +1864,7 @@ impl DeviceManager {
|
||||
self.modify_mode(f.as_raw_fd(), |t| unsafe { cfmakeraw(t) })
|
||||
}
|
||||
|
||||
fn listen_for_sigwinch_on_tty(&mut self, pty: &File) -> std::io::Result<()> {
|
||||
fn listen_for_sigwinch_on_tty(&mut self, pty_main: File, pty_sub: File) -> std::io::Result<()> {
|
||||
let seccomp_filter = get_seccomp_filter(
|
||||
&self.seccomp_action,
|
||||
Thread::PtyForeground,
|
||||
@ -1872,7 +1872,7 @@ impl DeviceManager {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
match start_sigwinch_listener(seccomp_filter, pty) {
|
||||
match start_sigwinch_listener(seccomp_filter, pty_main, pty_sub) {
|
||||
Ok(pipe) => {
|
||||
self.console_resize_pipe = Some(Arc::new(pipe));
|
||||
}
|
||||
@ -1903,18 +1903,19 @@ impl DeviceManager {
|
||||
let file = pty.main.try_clone().unwrap();
|
||||
self.console_pty = Some(Arc::new(Mutex::new(pty)));
|
||||
self.console_resize_pipe = resize_pipe.map(Arc::new);
|
||||
Endpoint::FilePair(file.try_clone().unwrap(), file)
|
||||
Endpoint::PtyPair(file.try_clone().unwrap(), file)
|
||||
} else {
|
||||
let (main, mut sub, path) =
|
||||
create_pty(false).map_err(DeviceManagerError::ConsolePtyOpen)?;
|
||||
create_pty().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();
|
||||
assert!(resize_pipe.is_none());
|
||||
self.listen_for_sigwinch_on_tty(&sub).unwrap();
|
||||
self.listen_for_sigwinch_on_tty(main.try_clone().unwrap(), sub)
|
||||
.unwrap();
|
||||
self.console_pty = Some(Arc::new(Mutex::new(PtyPair { main, path })));
|
||||
Endpoint::FilePair(file.try_clone().unwrap(), file)
|
||||
Endpoint::PtyPair(file.try_clone().unwrap(), file)
|
||||
}
|
||||
}
|
||||
ConsoleOutputMode::Tty => {
|
||||
@ -2010,7 +2011,7 @@ impl DeviceManager {
|
||||
self.serial_pty = Some(Arc::new(Mutex::new(pty)));
|
||||
} else {
|
||||
let (main, mut sub, path) =
|
||||
create_pty(true).map_err(DeviceManagerError::SerialPtyOpen)?;
|
||||
create_pty().map_err(DeviceManagerError::SerialPtyOpen)?;
|
||||
self.set_raw_mode(&mut sub)
|
||||
.map_err(DeviceManagerError::SetPtyRaw)?;
|
||||
self.config.lock().unwrap().serial.file = Some(path.clone());
|
||||
|
@ -57,9 +57,11 @@ fn unblock_all_signals() -> io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sigwinch_listener_main(seccomp_filter: BpfProgram, tx: File, tty: &File) -> ! {
|
||||
fn sigwinch_listener_main(seccomp_filter: BpfProgram, tx: File, pty: File) -> ! {
|
||||
TX.with(|opt| opt.replace(Some(tx)));
|
||||
|
||||
let pty_fd = pty.into_raw_fd();
|
||||
|
||||
unsafe {
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
@ -78,10 +80,13 @@ fn sigwinch_listener_main(seccomp_filter: BpfProgram, tx: File, tty: &File) -> !
|
||||
assert_ne!(setsid(), -1);
|
||||
|
||||
// Set the tty to be this process's controlling terminal.
|
||||
assert_ne!(ioctl(tty.as_raw_fd(), TIOCSCTTY, 0), -1);
|
||||
assert_ne!(ioctl(pty_fd, TIOCSCTTY, 0), -1);
|
||||
|
||||
// Become the foreground process group of the tty.
|
||||
assert_ne!(tcsetpgrp(tty.as_raw_fd(), getpgrp()), -1);
|
||||
assert_ne!(tcsetpgrp(pty_fd, getpgrp()), -1);
|
||||
|
||||
// Close the PTY fd
|
||||
assert_ne!(close(pty_fd), -1);
|
||||
}
|
||||
|
||||
notify();
|
||||
@ -109,7 +114,11 @@ fn sigwinch_listener_main(seccomp_filter: BpfProgram, tx: File, tty: &File) -> !
|
||||
exit(0);
|
||||
}
|
||||
|
||||
pub fn start_sigwinch_listener(seccomp_filter: BpfProgram, pty: &File) -> io::Result<File> {
|
||||
pub fn start_sigwinch_listener(
|
||||
seccomp_filter: BpfProgram,
|
||||
pty_main: File,
|
||||
pty_sub: File,
|
||||
) -> io::Result<File> {
|
||||
let mut pipe = [-1; 2];
|
||||
if unsafe { pipe2(pipe.as_mut_ptr(), O_CLOEXEC) } == -1 {
|
||||
return Err(io::Error::last_os_error());
|
||||
@ -125,7 +134,8 @@ pub fn start_sigwinch_listener(seccomp_filter: BpfProgram, pty: &File) -> io::Re
|
||||
-1 => return Err(io::Error::last_os_error()),
|
||||
0 => {
|
||||
drop(rx);
|
||||
sigwinch_listener_main(seccomp_filter, tx, pty);
|
||||
drop(pty_main);
|
||||
sigwinch_listener_main(seccomp_filter, tx, pty_sub);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user