Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add no console option #40

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

alexis-langlet
Copy link

@alexis-langlet alexis-langlet commented Mar 21, 2023

When a running VM stops, the VMM is blocked and never returns.
This is due to the epoll's loop (in lib.rs) that is used to listen to event and prompt stdin, the epoll::wait() being a blocking function.

In order to use the lib in another context (lambdo project), we need for the VMM to finish.
Moreover, we don't want to have output from VM being printed on our console.

To do that, we will allow to stop outputting to ttyS0 (if no console is specified)
And in case the VM stop running, we will stop the VMM

@alexis-langlet
Copy link
Author

@sameo we have a problem.

Everything is working with only one vCPU.
When we use 2 vCPUs, one thread stop but the other is hanging, so the VM never stops.
We've reduced the bug cause to the run function (src/vmm/src/cpu/mod.rs, line 223) it is probably what's blocking the thread and never return.

Is this a wanted behavior of ioctl ? what are we supposed to do ?

@alexis-langlet alexis-langlet force-pushed the add-no-console branch 2 times, most recently from 09d53d1 to 04ec86d Compare March 27, 2023 07:39
@alexis-langlet alexis-langlet marked this pull request as ready for review March 27, 2023 07:40
@alexis-langlet
Copy link
Author

@sameo we have a problem.

Everything is working with only one vCPU. When we use 2 vCPUs, one thread stop but the other is hanging, so the VM never stops. We've reduced the bug cause to the run function (src/vmm/src/cpu/mod.rs, line 223) it is probably what's blocking the thread and never return.

Is this a wanted behavior of ioctl ? what are we supposed to do ?

We've discussed the matter a bit further...
At first we thought that killing all thread at the end of the first one to finish could be an option, be because of a a potential deadlock we probably better not.
Because the blocking problem was already there with the console, we, in fact, have no regression... Is it possible to merge it as it is or do you see another option ?

@alexis-langlet
Copy link
Author

If it can help, here is the init file we use for testing

#! /bin/sh
mount -t devtmpfs dev /dev
mount -t proc proc /proc
mount -t sysfs sysfs /sys
ip link set up dev lo

echo "hello" > /dev/ttyS0
exit
poweroff -f

Copy link
Contributor

@sameo sameo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can not merge this PR for 3 reasons:

  1. It carries a bunch of unrelated commits.
  2. On the single commit that seems to be related to this PR, I have a few comments.
  3. You give no explanations about why is no_console needed.

src/main.rs Outdated Show resolved Hide resolved
// Call into KVM to launch (VMLAUNCH) or resume (VMRESUME) the virtual CPU.
// This is a blocking function, it only returns for either an error or a
// VM-Exit. In the latter case, we can inspect the exit reason.
match self.vcpu_fd.run() {
println!("Before running vCPU {}...", self.index);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please clean the debug logs up.

src/vmm/src/cpu/mod.rs Outdated Show resolved Hide resolved
src/vmm/src/cpu/mod.rs Outdated Show resolved Hide resolved
src/vmm/src/cpu/mod.rs Outdated Show resolved Hide resolved
src/vmm/src/lib.rs Outdated Show resolved Hide resolved
src/vmm/src/lib.rs Outdated Show resolved Hide resolved
EstebanBAR0N and others added 3 commits April 11, 2023 20:27
It is now possible to run a VM without a console with --no-console option

Co-authored-by: Esteban Baron <[email protected]>
Signed-off-by: Alexis Langlet <[email protected]>
(cherry picked from commit 9990b84)
Delete the no console attribute where not longer used

Co-authored-by: Esteban Baron <[email protected]>
Signed-off-by: Alexis Langlet <[email protected]>
(cherry picked from commit f144cbe)
@alexis-langlet
Copy link
Author

Thanks for your review! Everything should have been resolved and cleaned-up.

Copy link
Contributor

@sameo sameo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR brings a major change on how vCPU threads are managed (and potentially brutally killed). None of the three commits in it mention this. And none of the added code seems to come with any comments or explanation.
https://groups.google.com/g/comp.lang.c++/c/rYCO5yn4lXw/m/oITtSkZOtoUJ


unsafe { libc::exit(0) };
}
loop {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did we move the loop here to avoid passing the socket_name after each vm exit?

// The VM stopped (Shutdown ot HLT).
VcpuExit::Shutdown | VcpuExit::Hlt => {
println!("Guest shutdown: {:?}. Bye!", exit_reason);
unix_socket.write_all(b"1").unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We notify the main thread and then continue running?

Comment on lines +345 to +349
let mut unix_socket_name = String::from("/tmp/vmm.sock");
while Path::new(&unix_socket_name).exists() {
let rng = rand::rand_alphanumerics(8);
unix_socket_name = format!("/tmp/vmm-{}.sock", rng.to_str().unwrap());
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iiuc you're passing a named unix socket to the vcpu for it to check in when it get a shutdown/halt?
A simpler, more idiomatic approach is mpsc. And unless I'm missing why it would not work, I'd prefer that you use it. And yes, you may need to run a monitoring thread.


if connections.iter().any(|c| c.as_raw_fd() == event_data) {
use vmm_sys_util::signal::Killable;
handlers.iter().for_each(|handler| {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we're killing each thread whenever ones is shutdown/halted, right?

/// Access thread handler error
AccessThreadHandlerError,
/// Join thread error
JoinThreadError(Box<dyn Any + Send>),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unused.

@@ -86,6 +90,10 @@ pub enum Error {
VirtioNet(devices::net::VirtioNetError),
/// Error related to IOManager.
IoManager(vm_device::device_manager::Error),
/// Access thread handler error
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does that mean?

@@ -383,6 +427,14 @@ impl VMM {
.process_tap()
.map_err(Error::VirtioNet)?;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we still listening to stdin when the VM has no console?

Comment on lines +372 to +375
while connections.len() < total_cpus {
let connection = listener.accept().unwrap().0;
self.epoll.add_fd(connection.as_raw_fd()).unwrap();
connections.push(connection);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be a good place to explain what you're trying to do here: You're going to listen on a socket for any vcpu to halt and then do something about that information.

let mut connections: Vec<_> = Vec::new();

while connections.len() < total_cpus {
let connection = listener.accept().unwrap().0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please handle errors properly, by propagating them.


while connections.len() < total_cpus {
let connection = listener.accept().unwrap().0;
self.epoll.add_fd(connection.as_raw_fd()).unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants