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

vmm: Make gdb break/resuming more resilient #4363

Merged
merged 2 commits into from Jul 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
44 changes: 20 additions & 24 deletions vmm/src/cpu.rs
Expand Up @@ -1048,7 +1048,12 @@ impl CpuManager {
}

/// Start up as many vCPUs threads as needed to reach `desired_vcpus`
fn activate_vcpus(&mut self, desired_vcpus: u8, inserting: bool) -> Result<()> {
fn activate_vcpus(
&mut self,
desired_vcpus: u8,
inserting: bool,
paused: Option<bool>,
) -> Result<()> {
if desired_vcpus > self.config.max_vcpus {
return Err(Error::DesiredVCpuCountExceedsMax);
}
Expand All @@ -1057,11 +1062,16 @@ impl CpuManager {
(desired_vcpus - self.present_vcpus() + 1) as usize,
));

if let Some(paused) = paused {
self.vcpus_pause_signalled.store(paused, Ordering::SeqCst);
}

info!(
"Starting vCPUs: desired = {}, allocated = {}, present = {}",
"Starting vCPUs: desired = {}, allocated = {}, present = {}, paused = {}",
desired_vcpus,
self.vcpus.len(),
self.present_vcpus()
self.present_vcpus(),
self.vcpus_pause_signalled.load(Ordering::SeqCst)
);

// This reuses any inactive vCPUs as well as any that were newly created
Expand Down Expand Up @@ -1101,26 +1111,16 @@ impl CpuManager {
}

// Starts all the vCPUs that the VM is booting with. Blocks until all vCPUs are running.
pub fn start_boot_vcpus(&mut self) -> Result<()> {
self.activate_vcpus(self.boot_vcpus(), false)
pub fn start_boot_vcpus(&mut self, paused: bool) -> Result<()> {
self.activate_vcpus(self.boot_vcpus(), false, Some(paused))
}

pub fn start_restored_vcpus(&mut self) -> Result<()> {
let vcpu_numbers = self.vcpus.len() as u8;
let vcpu_thread_barrier = Arc::new(Barrier::new((vcpu_numbers + 1) as usize));
// Restore the vCPUs in "paused" state.
self.vcpus_pause_signalled.store(true, Ordering::SeqCst);
self.activate_vcpus(self.vcpus.len() as u8, false, Some(true))
.map_err(|e| {
Error::StartRestoreVcpu(anyhow!("Failed to start restored vCPUs: {:#?}", e))
})?;

for vcpu_id in 0..vcpu_numbers {
let vcpu = Arc::clone(&self.vcpus[vcpu_id as usize]);

self.start_vcpu(vcpu, vcpu_id, vcpu_thread_barrier.clone(), false)
.map_err(|e| {
Error::StartRestoreVcpu(anyhow!("Failed to start restored vCPUs: {:#?}", e))
})?;
}
// Unblock all restored CPU threads.
vcpu_thread_barrier.wait();
Ok(())
}

Expand All @@ -1136,7 +1136,7 @@ impl CpuManager {
match desired_vcpus.cmp(&self.present_vcpus()) {
cmp::Ordering::Greater => {
self.create_vcpus(desired_vcpus, None)?;
self.activate_vcpus(desired_vcpus, true)?;
self.activate_vcpus(desired_vcpus, true, None)?;
Ok(true)
}
cmp::Ordering::Less => {
Expand Down Expand Up @@ -1487,10 +1487,6 @@ impl CpuManager {
.map_err(Error::TranslateVirtualAddress)?;
Ok(gpa)
}

pub fn vcpus_paused(&self) -> bool {
self.vcpus_pause_signalled.load(Ordering::SeqCst)
}
}

struct Cpu {
Expand Down
36 changes: 10 additions & 26 deletions vmm/src/vm.rs
Expand Up @@ -2143,13 +2143,11 @@ impl Vm {
self.vm.tdx_finalize().map_err(Error::FinalizeTdx)?;
}

if new_state == VmState::Running {
self.cpu_manager
.lock()
.unwrap()
.start_boot_vcpus()
.map_err(Error::CpuManager)?;
}
self.cpu_manager
.lock()
.unwrap()
.start_boot_vcpus(new_state == VmState::BreakPoint)
.map_err(Error::CpuManager)?;

let mut state = self.state.try_write().map_err(|_| Error::PoisonedState)?;
*state = new_state;
Expand Down Expand Up @@ -2885,9 +2883,10 @@ impl Debuggable for Vm {
}

fn debug_pause(&mut self) -> std::result::Result<(), DebuggableError> {
if !self.cpu_manager.lock().unwrap().vcpus_paused() {
rbradford marked this conversation as resolved.
Show resolved Hide resolved
if *self.state.read().unwrap() == VmState::Running {
self.pause().map_err(DebuggableError::Pause)?;
}

let mut state = self
.state
.try_write()
Expand All @@ -2897,25 +2896,10 @@ impl Debuggable for Vm {
}

fn debug_resume(&mut self) -> std::result::Result<(), DebuggableError> {
if !self.cpu_manager.lock().unwrap().vcpus_paused() {
self.cpu_manager
.lock()
.unwrap()
.start_boot_vcpus()
.map_err(|e| {
DebuggableError::Resume(MigratableError::Resume(anyhow!(
"Could not start boot vCPUs: {:?}",
e
)))
})?;
} else {
self.resume().map_err(DebuggableError::Resume)?;
if *self.state.read().unwrap() == VmState::BreakPoint {
self.resume().map_err(DebuggableError::Pause)?;
}
let mut state = self
.state
.try_write()
.map_err(|_| DebuggableError::PoisonedState)?;
*state = VmState::Running;

Ok(())
}

Expand Down