Skip to content
New issue

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

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

Already on GitHub? # to your account

Thaw a paused container in cgroup v1 when it is forcely deleted. #1204

Merged
merged 2 commits into from
Oct 31, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions crates/libcontainer/src/container/container_delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,7 @@ impl Container {
self.refresh_status()
.context("failed to refresh container status")?;
if self.can_kill() && force {
let sig = signal::Signal::SIGKILL;
log::debug!("kill signal {} to {}", sig, self.pid().unwrap());
signal::kill(self.pid().unwrap(), sig)?;
self.do_kill(signal::Signal::SIGKILL, true)?;
self.set_status(ContainerStatus::Stopped).save()?;
}
log::debug!("container status: {:?}", self.status());
Expand Down Expand Up @@ -68,7 +66,7 @@ impl Container {
.with_context(|| "failed to run post stop hooks")?;
}
}
std::process::exit(0)
Ok(())
} else {
bail!(
"{} could not be deleted because it was {:?}",
Expand Down
102 changes: 76 additions & 26 deletions crates/libcontainer/src/container/container_kill.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::{Container, ContainerStatus};
use crate::signal::Signal;
use anyhow::{bail, Context, Result};
use libcgroups::common::create_cgroup_manager;
use libcgroups::common::{create_cgroup_manager, get_cgroup_setup};
use nix::sys::signal::{self};

impl Container {
Expand All @@ -24,37 +24,87 @@ impl Container {
/// # }
/// ```
pub fn kill<S: Into<Signal>>(&mut self, signal: S, all: bool) -> Result<()> {
let signal = signal.into().into_raw();

let pids = if all {
let cgroups_path = self.spec()?.cgroup_path;
let use_systemd = self
.systemd()
.context("container state does not contain cgroup manager")?;
let cmanger = create_cgroup_manager(&cgroups_path, use_systemd, self.id())?;
cmanger.get_all_pids()?
} else {
vec![self
.pid()
.context("failed to get the pid of the container")?]
};

self.refresh_status()
.context("failed to refresh container status")?;
if self.can_kill() {
pids.into_iter().try_for_each(|pid| {
log::debug!("kill signal {} to {}", signal, pid);
signal::kill(pid, signal)
})?;
self.do_kill(signal, all)?;
} else {
// just like runc, allow kill --all even if the container is stopped
if all && self.status() == ContainerStatus::Stopped {
self.do_kill(signal, all)?;
} else {
bail!(
"{} could not be killed because it was {:?}",
self.id(),
self.status()
)
}
}
self.set_status(ContainerStatus::Stopped).save()?;
Ok(())
}

self.set_status(ContainerStatus::Stopped).save()?;
std::process::exit(0)
pub(crate) fn do_kill<S: Into<Signal>>(&self, signal: S, all: bool) -> Result<()> {
if all {
self.kill_all_processes(signal)
} else {
bail!(
"{} could not be killed because it was {:?}",
self.kill_one_process(signal)
}
}

fn kill_one_process<S: Into<Signal>>(&self, signal: S) -> Result<()> {
let signal = signal.into().into_raw();
let pid = self.pid().unwrap();

log::debug!("kill signal {} to {}", signal, pid);
signal::kill(pid, signal)?;
// For cgroup V1, a frozon process cannot respond to signals,
// so we need to thaw it. Only thaw the cgroup for SIGKILL.
if self.status() == ContainerStatus::Paused && signal == signal::Signal::SIGKILL {
match get_cgroup_setup()? {
libcgroups::common::CgroupSetup::Legacy
| libcgroups::common::CgroupSetup::Hybrid => {
let cgroups_path = self.spec()?.cgroup_path;
let use_systemd = self
.systemd()
.context("container state does not contain cgroup manager")?;
let cmanger = create_cgroup_manager(&cgroups_path, use_systemd, self.id())?;
cmanger.freeze(libcgroups::common::FreezerState::Thawed)?;
}
libcgroups::common::CgroupSetup::Unified => {}
}
}
Ok(())
}

fn kill_all_processes<S: Into<Signal>>(&self, signal: S) -> Result<()> {
let signal = signal.into().into_raw();
let cgroups_path = self.spec()?.cgroup_path;
let use_systemd = self
.systemd()
.context("container state does not contain cgroup manager")?;
let cmanger = create_cgroup_manager(&cgroups_path, use_systemd, self.id())?;
let ret = cmanger.freeze(libcgroups::common::FreezerState::Frozen);
if ret.is_err() {
log::warn!(
"failed to freeze container {}, error: {}",
self.id(),
ret.unwrap_err()
);
}
let pids = cmanger.get_all_pids()?;
pids.iter().try_for_each(|&pid| {
log::debug!("kill signal {} to {}", signal, pid);
signal::kill(pid, signal)
})?;
let ret = cmanger.freeze(libcgroups::common::FreezerState::Thawed);
if ret.is_err() {
log::warn!(
"failed to thaw container {}, error: {}",
self.id(),
self.status()
)
ret.unwrap_err()
);
}
Ok(())
}
}