Skip to content

Commit b509d1b

Browse files
committed
virtio-console: Redirect init/kernel output to rust log
When we redirect the stdout of the guest it opens the question, where should init/kernel messages (things written to the console) go. It seems to make sense to write it as errors to the log, because for now the only messages that go there are errors.
1 parent e79c779 commit b509d1b

File tree

3 files changed

+52
-1
lines changed

3 files changed

+52
-1
lines changed

init/init.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,7 @@ int main(int argc, char **argv)
918918
}
919919

920920
if (execvp(exec_argv[0], exec_argv) < 0) {
921+
//TODO: maybe print this msg to the console not redirected stdout?
921922
printf("Couldn't execute '%s' inside the vm: %s\n", exec_argv[0], strerror(errno));
922923
exit(-3);
923924
}

src/devices/src/virtio/console/port_io.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::io::{self, ErrorKind};
22
use std::os::fd::{AsRawFd, FromRawFd, OwnedFd, RawFd};
33

44
use libc::{fcntl, F_GETFL, F_SETFL, O_NONBLOCK, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
5+
use log::Level;
56
use nix::errno::Errno;
67
use nix::poll::{poll, PollFd, PollFlags};
78
use nix::unistd::dup;
@@ -40,6 +41,10 @@ pub fn output_to_raw_fd_dup(fd: RawFd) -> Result<Box<dyn PortOutput + Send>, nix
4041
Ok(Box::new(PortOutputFd(fd)))
4142
}
4243

44+
pub fn output_to_log_as_err() -> Box<dyn PortOutput + Send> {
45+
Box::new(PortOutputLog::new())
46+
}
47+
4348
struct PortInputFd(OwnedFd);
4449

4550
impl AsRawFd for PortInputFd {
@@ -129,3 +134,48 @@ fn make_non_blocking(as_rw_fd: &impl AsRawFd) -> Result<(), nix::Error> {
129134
}
130135
Ok(())
131136
}
137+
138+
// Utility to relay log from the VM (the kernel boot log and messages from init)
139+
// to the rust log
140+
#[derive(Default)]
141+
pub struct PortOutputLog {
142+
buf: Vec<u8>,
143+
}
144+
145+
impl PortOutputLog {
146+
const FORCE_FLUSH_TRESHOLD: usize = 512;
147+
const LOG_TARGET: &'static str = "init_or_kernel";
148+
149+
fn new() -> Self {
150+
Self::default()
151+
}
152+
153+
fn force_flush(&mut self) {
154+
log::log!(target: PortOutputLog::LOG_TARGET, Level::Error, "[missing newline]{}", String::from_utf8_lossy(&self.buf));
155+
self.buf.clear();
156+
}
157+
}
158+
159+
impl PortOutput for PortOutputLog {
160+
fn write_volatile(&mut self, buf: &VolatileSlice) -> Result<usize, io::Error> {
161+
self.buf
162+
.write_volatile(buf)
163+
.map_err(|e| io::Error::new(ErrorKind::Other, e))?;
164+
165+
let mut start = 0;
166+
for (i, ch) in self.buf.iter().cloned().enumerate() {
167+
if ch == b'\n' {
168+
log::log!(target: PortOutputLog::LOG_TARGET, Level::Error, "{}", String::from_utf8_lossy(&self.buf[start..i]));
169+
start = i + 1;
170+
}
171+
}
172+
self.buf.drain(0..start);
173+
// Make sure to not grow the internal buffer forever!
174+
if self.buf.len() > PortOutputLog::FORCE_FLUSH_TRESHOLD {
175+
self.force_flush()
176+
}
177+
Ok(buf.len())
178+
}
179+
180+
fn wait_until_writable(&self) {}
181+
}

src/vmm/src/builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,7 @@ fn attach_console_devices(
10611061
output: if stdout_is_terminal {
10621062
Some(port_io::stdout().unwrap())
10631063
} else {
1064-
None
1064+
Some(port_io::output_to_log_as_err())
10651065
},
10661066
}];
10671067

0 commit comments

Comments
 (0)