-
Notifications
You must be signed in to change notification settings - Fork 433
Update LinuxIntelRdt to align with runtime-spec #3523
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
base: main
Are you sure you want to change the base?
Changes from all commits
0d826b5
544a499
3121e38
ebbe308
778071e
225c885
5dd4925
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,7 +12,9 @@ use super::{Container, ContainerStatus}; | |
| use crate::error::{CreateContainerError, LibcontainerError, MissingSpecError}; | ||
| use crate::notify_socket::NotifyListener; | ||
| use crate::process::args::{ContainerArgs, ContainerType}; | ||
| use crate::process::intel_rdt::delete_resctrl_subdirectory; | ||
| use crate::process::intel_rdt::{ | ||
| delete_resctrl_monitoring_subdirectory, delete_resctrl_subdirectory, | ||
| }; | ||
| use crate::process::{self}; | ||
| use crate::syscall::syscall::SyscallType; | ||
| use crate::user_ns::UserNamespaceConfig; | ||
|
|
@@ -192,7 +194,7 @@ impl ContainerBuilderImpl { | |
| pid_file: self.pid_file.to_owned(), | ||
| }; | ||
|
|
||
| let (init_pid, need_to_clean_up_intel_rdt_dir) = | ||
| let (init_pid, intel_rdt_dir, intel_rdt_monitoring_dir) = | ||
| process::container_main_process::container_main_process(&container_args).map_err( | ||
| |err| { | ||
| tracing::error!("failed to run container process {}", err); | ||
|
|
@@ -206,7 +208,8 @@ impl ContainerBuilderImpl { | |
| .set_status(ContainerStatus::Created) | ||
| .set_creator(nix::unistd::geteuid().as_raw()) | ||
| .set_pid(init_pid.as_raw()) | ||
| .set_clean_up_intel_rdt_directory(need_to_clean_up_intel_rdt_dir) | ||
| .set_intel_rdt_dir(intel_rdt_dir) | ||
| .set_intel_rdt_monitoring_dir(intel_rdt_monitoring_dir) | ||
| .save()?; | ||
| } | ||
|
|
||
|
|
@@ -231,9 +234,16 @@ impl ContainerBuilderImpl { | |
| } | ||
|
|
||
| if let Some(container) = &self.container { | ||
| if let Some(true) = container.clean_up_intel_rdt_subdirectory() { | ||
| if let Err(e) = delete_resctrl_subdirectory(container.id()) { | ||
| tracing::error!(id = ?container.id(), error = ?e, "failed to delete resctrl subdirectory"); | ||
| if let Some(path) = container.intel_rdt_monitoring_dir() { | ||
| if let Err(e) = delete_resctrl_monitoring_subdirectory(path) { | ||
| tracing::error!(path = ?path, error = ?e, "failed to delete resctrl monitoring subdirectory"); | ||
| errors.push(e.to_string()); | ||
| } | ||
| } | ||
|
|
||
| if let Some(path) = container.intel_rdt_dir() { | ||
| if let Err(e) = delete_resctrl_subdirectory(path) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since it throws an error when the file doesn't exist, it might be better not to return an error for
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will update the logic to handle the ErrorKind::NotFound case gracefully so that if the directory is already gone, it silently succeeds instead of throwing an error during teardown. |
||
| tracing::error!(path = ?path, error = ?e, "failed to delete resctrl subdirectory"); | ||
| errors.push(e.to_string()); | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,7 +8,9 @@ use super::{Container, ContainerStatus}; | |
| use crate::config::YoukiConfig; | ||
| use crate::error::LibcontainerError; | ||
| use crate::hooks; | ||
| use crate::process::intel_rdt::delete_resctrl_subdirectory; | ||
| use crate::process::intel_rdt::{ | ||
| delete_resctrl_monitoring_subdirectory, delete_resctrl_subdirectory, | ||
| }; | ||
|
|
||
| impl Container { | ||
| /// Deletes the container | ||
|
|
@@ -69,41 +71,12 @@ impl Container { | |
| // Once reached here, the container is verified that it can be deleted. | ||
| debug_assert!(self.status().can_delete()); | ||
|
|
||
| if let Some(true) = &self.clean_up_intel_rdt_subdirectory() { | ||
| if let Err(err) = delete_resctrl_subdirectory(self.id()) { | ||
| tracing::warn!( | ||
| "failed to delete resctrl subdirectory due to: {err:?}, continue to delete" | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| let mut config_opt = None; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the motivation behind changing
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The motivation behind introducing config_opt was simply to decouple the Intel RDT cleanup logic from the YoukiConfig processing block. I wanted to group the RDT teardown operations clearly before the cgroup and hooks teardown, similar to runc's teardown order. |
||
| if self.root.exists() { | ||
| match YoukiConfig::load(&self.root) { | ||
| Ok(config) => { | ||
| tracing::debug!("config: {:?}", config); | ||
|
|
||
| // remove the cgroup created for the container | ||
| // check https://man7.org/linux/man-pages/man7/cgroups.7.html | ||
| // creating and removing cgroups section for more information on cgroups | ||
| let cmanager = libcgroups::common::create_cgroup_manager( | ||
| libcgroups::common::CgroupConfig { | ||
| cgroup_path: config.cgroup_path.to_owned(), | ||
| systemd_cgroup: self.systemd(), | ||
| container_name: self.id().to_string(), | ||
| }, | ||
| )?; | ||
| cmanager.remove().map_err(|err| { | ||
| tracing::error!(cgroup_path = ?config.cgroup_path, "failed to remove cgroup due to: {err:?}"); | ||
| err | ||
| })?; | ||
|
|
||
| if let Some(hooks) = config.hooks.as_ref() { | ||
| hooks::run_hooks(hooks.poststop().as_ref(), Some(&self.state), None, None) | ||
| .map_err(|err| { | ||
| tracing::error!(err = ?err, "failed to run post stop hooks"); | ||
| err | ||
| })?; | ||
| } | ||
| tracing::debug!("config: {config:?}"); | ||
| config_opt = Some(config); | ||
| } | ||
| Err(err) => { | ||
| // There is a brief window where the container state is | ||
|
|
@@ -115,7 +88,49 @@ impl Container { | |
| ); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if let Some(path) = self.intel_rdt_monitoring_dir() { | ||
| if let Err(err) = delete_resctrl_monitoring_subdirectory(path) { | ||
| tracing::warn!( | ||
| "failed to delete resctrl monitoring subdirectory due to: {err:?}, continue to delete" | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| if let Some(path) = self.intel_rdt_dir() { | ||
| if let Err(err) = delete_resctrl_subdirectory(path) { | ||
| tracing::warn!( | ||
| "failed to delete resctrl subdirectory due to: {err:?}, continue to delete" | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| if let Some(config) = config_opt { | ||
| // remove the cgroup created for the container | ||
| // check https://man7.org/linux/man-pages/man7/cgroups.7.html | ||
| // creating and removing cgroups section for more information on cgroups | ||
| let cmanager = | ||
| libcgroups::common::create_cgroup_manager(libcgroups::common::CgroupConfig { | ||
| cgroup_path: config.cgroup_path.to_owned(), | ||
| systemd_cgroup: self.systemd(), | ||
| container_name: self.id().to_string(), | ||
| })?; | ||
| cmanager.remove().map_err(|err| { | ||
| tracing::error!(cgroup_path = ?config.cgroup_path, "failed to remove cgroup due to: {err:?}"); | ||
| err | ||
| })?; | ||
|
|
||
| if let Some(hooks) = config.hooks.as_ref() { | ||
| hooks::run_hooks(hooks.poststop().as_ref(), Some(&self.state), None, None) | ||
| .map_err(|err| { | ||
| tracing::error!(err = ?err, "failed to run post stop hooks"); | ||
| err | ||
| })?; | ||
| } | ||
| } | ||
|
|
||
| if self.root.exists() { | ||
| // remove the directory storing container state | ||
| tracing::debug!("remove dir {:?}", self.root); | ||
| fs::remove_dir_all(&self.root).map_err(|err| { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -119,8 +119,14 @@ pub struct State { | |
| pub creator: Option<u32>, | ||
| // Specifies if systemd should be used to manage cgroups | ||
| pub use_systemd: bool, | ||
| // Specifies if the Intel RDT subdirectory needs be cleaned up. | ||
| pub clean_up_intel_rdt_subdirectory: Option<bool>, | ||
| // Specifies the Intel RDT subdirectory path that needs to be cleaned up. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The logic here implies that this path exists when a deletion is required. Could you rename it to something that makes this intent clearer? Also, what was the motivation behind using a path instead of a bool as the state's responsibility?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To answer the second part first regarding the motivation for using a path instead of a boolean flag: This was done to match runc's approach. runc stores the explicit filesystem paths (IntelRdtPath and IntelRdtMonPath) directly in its linuxContainer state structure. Since youki aims for compatibility, saving the explicit paths avoids complex dynamic reconstruction of those paths during container deletion (which requires re-evaluating the spec, closID, etc.). Regarding the naming: I just followed how runc named them (intel_rdt_path and intel_rdt_mon_path). |
||
| pub intel_rdt_dir: Option<PathBuf>, | ||
| /// Indicates the dedicated monitoring group subdirectory (`mon_groups/<container_id>`) | ||
| /// within the resctrl filesystem that needs to be cleaned up. | ||
| /// As per OCI runtime-spec v1.3.0, if `enable_monitoring` is true, the runtime MUST | ||
| /// create this group and MUST remove it when the container is deleted. | ||
| #[serde(skip_serializing_if = "Option::is_none")] | ||
| pub intel_rdt_monitoring_dir: Option<PathBuf>, | ||
| } | ||
|
|
||
| impl State { | ||
|
|
@@ -142,7 +148,8 @@ impl State { | |
| created: None, | ||
| creator: None, | ||
| use_systemd: false, | ||
| clean_up_intel_rdt_subdirectory: None, | ||
| intel_rdt_dir: None, | ||
| intel_rdt_monitoring_dir: None, | ||
| } | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the motivation behind changing the return value here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My motivation for changing the return value to pass intel_rdt_dir and intel_rdt_monitoring_dir and storing these paths directly in state.json was to closely mirror how runc implements this.
runc explicitly stores both IntelRdtPath and IntelRdtMonPath directly in its container state object, and relies on those saved paths when it needs to clean up the directories during teardown.
You can see runc storing the paths in the state here:
https://github.com/opencontainers/runc/blob/main/libcontainer/container_linux.go#L79