-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9ac1f26
commit cc3b2bb
Showing
5 changed files
with
199 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
use containerd_shim::{ | ||
error::{Error, Result}, | ||
io_error, other_error, | ||
}; | ||
use std::path::Path; | ||
use tokio::{ | ||
fs::{self, File}, | ||
io::{AsyncBufReadExt, AsyncReadExt, BufReader}, | ||
sync::mpsc::{self, Receiver}, | ||
}; | ||
|
||
use std::os::unix::io::{AsRawFd, FromRawFd}; | ||
|
||
pub async fn get_path_from_cgorup(pid: u32) -> Result<String> { | ||
let proc_path = format!("/proc/{}/cgroup", pid); | ||
let file = File::open(proc_path.clone()) | ||
.await | ||
.map_err(io_error!(e, "open {}.", proc_path))?; | ||
let mut lines = BufReader::new(file).lines(); | ||
while let Some(line) = | ||
lines | ||
.next_line() | ||
.await | ||
.map_err(io_error!(e, "read file {} failed.", proc_path))? | ||
{ | ||
if line.contains("memory") { | ||
let parts: Vec<&str> = line.split(':').collect(); | ||
if let Some(path) = parts.last() { | ||
return Ok(path.to_string()); | ||
} | ||
break; | ||
} | ||
} | ||
Err("Memory cgroup path not found").map_err(other_error!(e, "Error get path:"))? | ||
} | ||
|
||
pub async fn get_existing_cgroup_mem_path(pid_path: String) -> Result<(String, String)> { | ||
let mut mountinfo_path = get_path_from_mountinfo().await?; | ||
if mountinfo_path.0 == "/" { | ||
mountinfo_path.0 = String::from(""); | ||
} | ||
let res = pid_path.trim_start_matches(&mountinfo_path.0).to_string(); | ||
Ok((res, mountinfo_path.1)) | ||
} | ||
|
||
async fn get_path_from_mountinfo() -> Result<(String, String)> { | ||
let mountinfo_file = File::open("/proc/self/mountinfo".clone()) | ||
.await | ||
.map_err(io_error!(e, "open {}", "/proc/self/mountinfo"))?; | ||
|
||
// for line in BufReader::new(mountinfo_file).lines() { | ||
let mut lines = BufReader::new(mountinfo_file).lines(); | ||
while let Some(line) = lines | ||
.next_line() | ||
.await | ||
.map_err(io_error!(e, "read file /proc/self/mountinfo failed."))? | ||
{ | ||
if line.contains("cgroup") && line.contains("memory") { | ||
return parse_memory_mountroot(&line); | ||
} | ||
} | ||
|
||
Err("No memory found in mountinfo file.") | ||
.map_err(other_error!(e, "Error get path from montinfo:"))? | ||
} | ||
|
||
fn parse_memory_mountroot(line: &str) -> Result<(String, String)> { | ||
let s_values: Vec<_> = line.split(" - ").collect(); | ||
if s_values.len() != 2 { | ||
return Err("Parse from mountinfo failed") | ||
.map_err(other_error!(e, "Error get path from montinfo:"))?; | ||
} | ||
|
||
let s0_values: Vec<_> = s_values[0].trim().split(' ').collect(); | ||
if s0_values.len() < 6 { | ||
return Err("Parse from mountinfo failed") | ||
.map_err(other_error!(e, "Error get path from montinfo:"))?; | ||
} | ||
Ok((s0_values[3].to_string(), s0_values[4].to_string())) | ||
} | ||
|
||
pub async fn register_memory_event_v1(key: &str, dir: &Path) -> Result<Receiver<String>> { | ||
register_memory_event(key, dir, "memory.oom_control", "").await | ||
} | ||
|
||
async fn register_memory_event( | ||
key: &str, | ||
cg_dir: &Path, | ||
event_name: &str, | ||
arg: &str, | ||
) -> Result<Receiver<String>> { | ||
let path = cg_dir.join(event_name); | ||
let event_file = fs::File::open(path.clone()) | ||
.await | ||
.map_err(other_error!(e, "Error get path:"))?; | ||
|
||
let eventfd = unsafe { libc::eventfd(0, libc::EFD_CLOEXEC) }; | ||
|
||
let event_control_path = cg_dir.join("cgroup.event_control"); | ||
let data = if arg.is_empty() { | ||
format!("{} {}", eventfd, event_file.as_raw_fd()) | ||
} else { | ||
format!("{} {} {}", eventfd, event_file.as_raw_fd(), arg) | ||
}; | ||
fs::write(&event_control_path, data.clone()) | ||
.await | ||
.map_err(other_error!(e, "Error write eventfd:"))?; | ||
|
||
let mut buf = [0u8; 8]; | ||
|
||
let (sender, receiver) = mpsc::channel(128); | ||
let key = key.to_string(); | ||
let mut eventfd_file = unsafe { File::from_raw_fd(eventfd) }; | ||
tokio::spawn(async move { | ||
loop { | ||
match eventfd_file.read(&mut buf).await { | ||
Ok(bytes_read) => { | ||
if bytes_read == 0 { | ||
return; | ||
} | ||
} | ||
Err(_) => { | ||
return; | ||
} | ||
} | ||
if !Path::new(&event_control_path).exists() { | ||
return; | ||
} | ||
sender.send(key.clone()).await.unwrap(); | ||
} | ||
}); | ||
|
||
Ok(receiver) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters