mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-08-31 08:28:34 +00:00
runtime-rs: ch: Implement full thread/tid/pid handling
Add in the full details once cloud-hypervisor/cloud-hypervisor#6103 has been implemented, and the feature is available in a Cloud Hypervisor release. Fixes: #8799 Signed-off-by: David Esparza <david.esparza.borquez@intel.com>
This commit is contained in:
22
src/runtime-rs/Cargo.lock
generated
22
src/runtime-rs/Cargo.lock
generated
@@ -1654,6 +1654,7 @@ dependencies = [
|
||||
"shim-interface",
|
||||
"slog",
|
||||
"slog-scope",
|
||||
"tempdir",
|
||||
"test-utils",
|
||||
"tests_utils",
|
||||
"thiserror",
|
||||
@@ -2749,7 +2750,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "059a34f111a9dee2ce1ac2826a68b24601c4298cfeb1a587c3cb493d5ab46f52"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"nix 0.26.2",
|
||||
"nix 0.27.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3163,6 +3164,15 @@ version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.20"
|
||||
@@ -3919,6 +3929,16 @@ dependencies = [
|
||||
"xattr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempdir"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
||||
dependencies = [
|
||||
"rand 0.4.6",
|
||||
"remove_dir_all",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.7.0"
|
||||
|
@@ -41,6 +41,7 @@ tests_utils = { path = "../../tests/utils" }
|
||||
futures = "0.3.25"
|
||||
safe-path = "0.1.0"
|
||||
crossbeam-channel = "0.5.6"
|
||||
tempdir = "0.3.7"
|
||||
|
||||
[target.'cfg(not(target_arch = "s390x"))'.dependencies]
|
||||
dragonball = { path = "../../../dragonball", features = ["atomic-guest-memory", "virtio-vsock", "hotplug", "virtio-blk", "virtio-net", "virtio-fs", "vhost-net", "dbs-upcall", "virtio-mem", "virtio-balloon", "vhost-user-net", "host-device"] }
|
||||
|
@@ -30,6 +30,7 @@ use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::fs;
|
||||
use std::fs::create_dir_all;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::os::unix::net::UnixStream;
|
||||
@@ -677,13 +678,10 @@ impl CloudHypervisorInner {
|
||||
}
|
||||
|
||||
pub(crate) async fn get_thread_ids(&self) -> Result<VcpuThreadIds> {
|
||||
let mut vcpus = HashMap::new();
|
||||
|
||||
let vcpu = 0;
|
||||
let thread_id = self.get_vmm_master_tid().await?;
|
||||
let proc_path = format!("/proc/{thread_id}");
|
||||
|
||||
vcpus.insert(vcpu, thread_id);
|
||||
|
||||
let vcpus = get_ch_vcpu_tids(&proc_path)?;
|
||||
let vcpu_thread_ids = VcpuThreadIds { vcpus };
|
||||
|
||||
Ok(vcpu_thread_ids)
|
||||
@@ -908,6 +906,59 @@ fn get_guest_protection() -> Result<GuestProtection> {
|
||||
Ok(guest_protection)
|
||||
}
|
||||
|
||||
// Return a TID/VCPU map from a specified /proc/{pid} path.
|
||||
fn get_ch_vcpu_tids(proc_path: &str) -> Result<HashMap<u32, u32>> {
|
||||
const VCPU_STR: &str = "vcpu";
|
||||
|
||||
let src = std::fs::canonicalize(proc_path)
|
||||
.map_err(|e| anyhow!("Invalid proc path: {proc_path}: {e}"))?;
|
||||
|
||||
let tid_path = src.join("task");
|
||||
|
||||
let mut vcpus = HashMap::new();
|
||||
|
||||
for entry in fs::read_dir(&tid_path)? {
|
||||
let entry = entry?;
|
||||
|
||||
let tid_str = match entry.file_name().into_string() {
|
||||
Ok(id) => id,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let tid = tid_str
|
||||
.parse::<u32>()
|
||||
.map_err(|e| anyhow!(e).context("invalid tid."))?;
|
||||
|
||||
let comm_path = tid_path.join(tid_str.clone()).join("comm");
|
||||
|
||||
if !comm_path.exists() {
|
||||
return Err(anyhow!("comm path was not found."));
|
||||
}
|
||||
|
||||
let p_name = fs::read_to_string(comm_path)?;
|
||||
|
||||
// The CH names it's threads with a vcpu${number} to identify them, where
|
||||
// the thread name is located at /proc/${ch_pid}/task/${thread_id}/comm.
|
||||
if !p_name.starts_with(VCPU_STR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let vcpu_id = p_name
|
||||
.trim_start_matches(VCPU_STR)
|
||||
.trim()
|
||||
.parse::<u32>()
|
||||
.map_err(|e| anyhow!(e).context("Invalid vcpu id."))?;
|
||||
|
||||
vcpus.insert(tid, vcpu_id);
|
||||
}
|
||||
|
||||
if vcpus.is_empty() {
|
||||
return Err(anyhow!("The contents of proc path are not available."));
|
||||
}
|
||||
|
||||
Ok(vcpus)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -922,6 +973,9 @@ mod tests {
|
||||
use std::path::PathBuf;
|
||||
use test_utils::{assert_result, skip_if_not_root};
|
||||
|
||||
use std::fs::File;
|
||||
use tempdir::TempDir;
|
||||
|
||||
fn set_fake_guest_protection(protection: Option<GuestProtection>) {
|
||||
let existing_ref = FAKE_GUEST_PROTECTION.clone();
|
||||
|
||||
@@ -1333,4 +1387,58 @@ mod tests {
|
||||
assert_eq!(d.level, level, "{}", msg);
|
||||
}
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_get_thread_ids() {
|
||||
let path_dir = "/tmp/proc";
|
||||
let file_name = "1";
|
||||
|
||||
let tmp_dir = TempDir::new(path_dir).unwrap();
|
||||
let file_path = tmp_dir.path().join(file_name);
|
||||
let _tmp_file = File::create(file_path.as_os_str()).unwrap();
|
||||
let file_path_name = file_path.as_path().to_str().map(|s| s.to_string());
|
||||
let file_path_name_str = file_path_name.as_ref().unwrap().to_string();
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TestData<'a> {
|
||||
proc_path: &'a str,
|
||||
result: Result<HashMap<u32, u32>>,
|
||||
}
|
||||
|
||||
let tests = &[
|
||||
TestData {
|
||||
// Test on a non-existent directory.
|
||||
proc_path: path_dir,
|
||||
result: Err(anyhow!(
|
||||
"Invalid proc path: {path_dir}: No such file or directory (os error 2)"
|
||||
)),
|
||||
},
|
||||
TestData {
|
||||
// Test on an existing path, however it is not valid because it does not point to a pid.
|
||||
proc_path: &file_path_name_str,
|
||||
result: Err(anyhow!("Not a directory (os error 20)")),
|
||||
},
|
||||
TestData {
|
||||
// Test on an existing proc/${pid} but that does not correspond to a CH pid.
|
||||
proc_path: "/proc/1",
|
||||
result: Err(anyhow!("The contents of proc path are not available.")),
|
||||
},
|
||||
];
|
||||
|
||||
for (i, d) in tests.iter().enumerate() {
|
||||
let msg = format!("test: [{}]: {:?}", i, d);
|
||||
|
||||
if std::env::var("DEBUG").is_ok() {
|
||||
println!("DEBUG: {msg}");
|
||||
}
|
||||
|
||||
let result = get_ch_vcpu_tids(d.proc_path);
|
||||
let msg = format!("{}, result: {:?}", msg, result);
|
||||
|
||||
let expected_error = format!("{}", d.result.as_ref().unwrap_err());
|
||||
let actual_error = format!("{}", result.unwrap_err());
|
||||
|
||||
assert!(actual_error == expected_error, "{}", msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user