From 6fa7ab3476ceb6f600e3b787764f28d1fedf1564 Mon Sep 17 00:00:00 2001 From: Michael Schleicher Date: Tue, 20 Aug 2024 11:22:42 +0000 Subject: [PATCH 1/9] feat: :sparkles: add drops column to udp entries --- procfs-core/src/net.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/procfs-core/src/net.rs b/procfs-core/src/net.rs index 7689d1b..a68142c 100644 --- a/procfs-core/src/net.rs +++ b/procfs-core/src/net.rs @@ -152,6 +152,7 @@ pub struct UdpNetEntry { pub tx_queue: u32, pub uid: u32, pub inode: u64, + pub drops: u64, } /// An entry in the Unix socket table @@ -295,6 +296,9 @@ impl super::FromBufReadSI for UdpNetEntries { let uid = from_str!(u32, expect!(s.next(), "udp::uid")); s.next(); // skip timeout let inode = expect!(s.next(), "udp::inode"); + s.next(); // skip ref + s.next(); // skip pointer + let drops = expect!(s.next(), "udp::drops"); vec.push(UdpNetEntry { local_address: parse_addressport_str(local_address, system_info.is_little_endian())?, @@ -304,6 +308,7 @@ impl super::FromBufReadSI for UdpNetEntries { state: expect!(UdpState::from_u8(from_str!(u8, state, 16))), uid, inode: from_str!(u64, inode), + drops: from_str!(u64, drops), }); } @@ -1728,4 +1733,26 @@ UdpLite: 0 0 0 0 0 0 0 0 0 let res = Snmp::from_read(r).unwrap(); println!("{res:?}"); } + + #[test] + fn test_udp_drops_debian_12() { + let data = r#" sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops + 624: 00000000:D77C 00000000:0000 07 00000000:00000000 00:00000000 00000000 104 0 3719666 2 000000008fba5196 0 + 824: 00000000:0044 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 14796 2 0000000051381d39 0 + 918: 00000000:00A2 00000000:0000 07 00000000:00000000 00:00000000 00000000 104 0 3719670 2 0000000048ae40a7 0 + 1270: 00000000:0202 00000000:0000 07 00000000:00000000 00:00000000 00000000 104 0 3719665 2 00000000357eb7c3 0 + 1357: 00000000:AA59 00000000:0000 07 00000000:00000000 00:00000000 00000000 104 0 3719668 2 000000000ed7b854 0"#; + let r = std::io::Cursor::new(data.as_bytes()); + use crate::FromBufReadSI; + let res = UdpNetEntries::from_buf_read( + r, + &crate::ExplicitSystemInfo { + boot_time_secs: 0, + ticks_per_second: 0, + page_size: 0, + is_little_endian: true, + }, + ); + assert!(res.is_ok()) + } } From 56a5e194d9ab0eb60433b1078b7d43b32bcb8c6a Mon Sep 17 00:00:00 2001 From: Michael Schleicher Date: Mon, 26 Aug 2024 07:43:02 +0000 Subject: [PATCH 2/9] feat: :sparkles: Use kernel version to determine if /proc/net/udp drops column can be read Kernels prior to 2.6.27 do not provide a drops column for /proc/net/udp therefore a check is introduced to validate the current kernel version before reading the column Add kernel version to SystemInfoInterface --- procfs-core/src/lib.rs | 6 ++++ procfs-core/src/net.rs | 62 +++++++++++++++++++++++++++--------- procfs/src/lib.rs | 4 +++ procfs/src/sys/kernel/mod.rs | 8 ++++- 4 files changed, 64 insertions(+), 16 deletions(-) diff --git a/procfs-core/src/lib.rs b/procfs-core/src/lib.rs index 34c77cf..769ad13 100644 --- a/procfs-core/src/lib.rs +++ b/procfs-core/src/lib.rs @@ -255,6 +255,7 @@ pub trait SystemInfoInterface { fn page_size(&self) -> u64; /// Whether the system is little endian (true) or big endian (false). fn is_little_endian(&self) -> bool; + fn kernel_version(&self) -> ProcResult; #[cfg(feature = "chrono")] fn boot_time(&self) -> ProcResult> { @@ -275,6 +276,7 @@ pub struct ExplicitSystemInfo { pub ticks_per_second: u64, pub page_size: u64, pub is_little_endian: bool, + pub kernel_version: KernelVersion, } impl SystemInfoInterface for ExplicitSystemInfo { @@ -293,6 +295,10 @@ impl SystemInfoInterface for ExplicitSystemInfo { fn is_little_endian(&self) -> bool { self.is_little_endian } + + fn kernel_version(&self) -> ProcResult { + Ok(self.kernel_version) + } } /// Values which can provide an output given the [SystemInfo]. diff --git a/procfs-core/src/net.rs b/procfs-core/src/net.rs index a68142c..7fd87d2 100644 --- a/procfs-core/src/net.rs +++ b/procfs-core/src/net.rs @@ -6,11 +6,10 @@ //! //! This module corresponds to the `/proc/net` directory and contains various information about the //! networking layer. -use crate::ProcResult; use crate::{build_internal_error, expect, from_iter, from_str}; -use std::collections::HashMap; - +use crate::{KernelVersion, ProcResult}; use bitflags::bitflags; +use std::collections::HashMap; use std::io::BufRead; use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; use std::{path::PathBuf, str::FromStr}; @@ -296,9 +295,15 @@ impl super::FromBufReadSI for UdpNetEntries { let uid = from_str!(u32, expect!(s.next(), "udp::uid")); s.next(); // skip timeout let inode = expect!(s.next(), "udp::inode"); - s.next(); // skip ref - s.next(); // skip pointer - let drops = expect!(s.next(), "udp::drops"); + + let drops = match system_info.kernel_version() { + Ok(version) if version >= KernelVersion::new(2, 6, 27) => { + s.next(); // skip ref + s.next(); // skip pointer + expect!(s.next(), "udp::drops") + } + _ => "0", // Fallback if the kernel version does not support the drops column or the kernel version could not be read + }; vec.push(UdpNetEntry { local_address: parse_addressport_str(local_address, system_info.is_little_endian())?, @@ -1735,24 +1740,51 @@ UdpLite: 0 0 0 0 0 0 0 0 0 } #[test] - fn test_udp_drops_debian_12() { - let data = r#" sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops - 624: 00000000:D77C 00000000:0000 07 00000000:00000000 00:00000000 00000000 104 0 3719666 2 000000008fba5196 0 - 824: 00000000:0044 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 14796 2 0000000051381d39 0 - 918: 00000000:00A2 00000000:0000 07 00000000:00000000 00:00000000 00000000 104 0 3719670 2 0000000048ae40a7 0 - 1270: 00000000:0202 00000000:0000 07 00000000:00000000 00:00000000 00000000 104 0 3719665 2 00000000357eb7c3 0 - 1357: 00000000:AA59 00000000:0000 07 00000000:00000000 00:00000000 00000000 104 0 3719668 2 000000000ed7b854 0"#; + fn test_udp_drops_debian_kernel_version_greater_2_6_27() { + let expected_drops = 42; + let data = format!( + r#" sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode ref pointer drops + 1270: 00000000:0202 00000000:0000 07 00000000:00000000 00:00000000 00000000 104 0 3719665 2 00000000357eb7c3 {expected_drops}"# + ); let r = std::io::Cursor::new(data.as_bytes()); use crate::FromBufReadSI; - let res = UdpNetEntries::from_buf_read( + let entries = UdpNetEntries::from_buf_read( r, &crate::ExplicitSystemInfo { boot_time_secs: 0, ticks_per_second: 0, page_size: 0, is_little_endian: true, + kernel_version: "2.6.27".parse().unwrap(), }, + ) + .unwrap(); + let entry = entries.0.first().unwrap(); + + assert_eq!(entry.drops, expected_drops) + } + + #[test] + fn test_udp_drops_debian_kernel_version_smaller_2_6_27() { + let data = format!( + r#" sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode + 1270: 00000000:0202 00000000:0000 07 00000000:00000000 00:00000000 00000000 104 0 3719665"# ); - assert!(res.is_ok()) + let r = std::io::Cursor::new(data.as_bytes()); + use crate::FromBufReadSI; + let entries = UdpNetEntries::from_buf_read( + r, + &crate::ExplicitSystemInfo { + boot_time_secs: 0, + ticks_per_second: 0, + page_size: 0, + is_little_endian: true, + kernel_version: "2.6.26".parse().unwrap(), + }, + ) + .unwrap(); + let entry = entries.0.first().unwrap(); + + assert_eq!(entry.drops, 0) } } diff --git a/procfs/src/lib.rs b/procfs/src/lib.rs index 05737be..530a2b1 100644 --- a/procfs/src/lib.rs +++ b/procfs/src/lib.rs @@ -93,6 +93,10 @@ impl SystemInfoInterface for LocalSystemInfo { fn is_little_endian(&self) -> bool { u16::from_ne_bytes([0, 1]).to_le_bytes() == [0, 1] } + + fn kernel_version(&self) -> ProcResult { + KernelVersion::cached().map(Into::into) + } } const LOCAL_SYSTEM_INFO: LocalSystemInfo = LocalSystemInfo; diff --git a/procfs/src/sys/kernel/mod.rs b/procfs/src/sys/kernel/mod.rs index e069d5e..ccf4f1b 100644 --- a/procfs/src/sys/kernel/mod.rs +++ b/procfs/src/sys/kernel/mod.rs @@ -66,7 +66,7 @@ impl Version { Self { major, minor, - patch: u16::from_ne_bytes([lo, hi]) + patch: u16::from_ne_bytes([lo, hi]), } } @@ -145,6 +145,12 @@ impl cmp::PartialOrd for Version { } } +impl From for procfs_core::KernelVersion { + fn from(value: Version) -> Self { + Self::new(value.major, value.minor, value.patch) + } +} + /// Represents a kernel type #[derive(Debug, Clone, Eq, PartialEq)] pub struct Type { From 992e88aef374b3e0ba795f63a10c8fdb8d3ea0b5 Mon Sep 17 00:00:00 2001 From: Michael Schleicher Date: Fri, 25 Oct 2024 14:18:47 +0200 Subject: [PATCH 3/9] fix: :bug: add serde to kernel version struct --- procfs-core/src/lib.rs | 1 + procfs-core/src/sys/kernel/mod.rs | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/procfs-core/src/lib.rs b/procfs-core/src/lib.rs index 769ad13..256d3c7 100644 --- a/procfs-core/src/lib.rs +++ b/procfs-core/src/lib.rs @@ -276,6 +276,7 @@ pub struct ExplicitSystemInfo { pub ticks_per_second: u64, pub page_size: u64, pub is_little_endian: bool, + #[cfg_attr(feature = "serde1", serde(skip))] pub kernel_version: KernelVersion, } diff --git a/procfs-core/src/sys/kernel/mod.rs b/procfs-core/src/sys/kernel/mod.rs index 7d1b249..e3953e8 100644 --- a/procfs-core/src/sys/kernel/mod.rs +++ b/procfs-core/src/sys/kernel/mod.rs @@ -7,12 +7,16 @@ use std::cmp; use std::collections::HashSet; use std::str::FromStr; +#[cfg(feature = "serde1")] +use serde::{Deserialize, Serialize}; + use bitflags::bitflags; use crate::{ProcError, ProcResult}; /// Represents a kernel version, in major.minor.release version. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)] +#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] pub struct Version { pub major: u8, pub minor: u8, From 7696d497435ac9ad4a81dacf53412c9452453a90 Mon Sep 17 00:00:00 2001 From: Michael Schleicher Date: Mon, 28 Oct 2024 03:56:54 -0400 Subject: [PATCH 4/9] fix: :rotating_light: fix linter warning for unkown feature In rust 1.80 compile-time checks for unkown features are introduced. Therefore workspace lints for unkown features are enabled. --- Cargo.toml | 3 +++ procfs/Cargo.toml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index d8964f0..86c3b74 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,6 @@ categories = ["os::unix-apis", "filesystem"] license = "MIT OR Apache-2.0" edition = "2018" rust-version = "1.70" + +[workspace.lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tarpaulin)'] } diff --git a/procfs/Cargo.toml b/procfs/Cargo.toml index bdf2630..af76550 100644 --- a/procfs/Cargo.toml +++ b/procfs/Cargo.toml @@ -39,3 +39,6 @@ rustdoc-args = ["--generate-link-to-definition"] [[bench]] name = "cpuinfo" harness = false + +[lints] +workspace = true From e34b38ba8a3eeeb884b670758b4cadec5ff9f774 Mon Sep 17 00:00:00 2001 From: Michael Schleicher Date: Mon, 28 Oct 2024 04:07:43 -0400 Subject: [PATCH 5/9] fix: :rotating_light: use `Current` for cpuinfo benchmark --- procfs/benches/cpuinfo.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/procfs/benches/cpuinfo.rs b/procfs/benches/cpuinfo.rs index c1ff02b..5cfd866 100644 --- a/procfs/benches/cpuinfo.rs +++ b/procfs/benches/cpuinfo.rs @@ -1,10 +1,11 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; use procfs::CpuInfo; +use procfs::Current; fn bench_cpuinfo(c: &mut Criterion) { - c.bench_function("CpuInfo::new", |b| b.iter(|| black_box(CpuInfo::new().unwrap()))); + c.bench_function("CpuInfo::current", |b| b.iter(|| black_box(CpuInfo::current().unwrap()))); - let cpuinfo = black_box(CpuInfo::new().unwrap()); + let cpuinfo = black_box(CpuInfo::current().unwrap()); c.bench_function("CpuInfo::get_info", |b| b.iter(|| black_box(cpuinfo.get_info(0)))); c.bench_function("CpuInfo::model_name", |b| b.iter(|| cpuinfo.model_name(0))); c.bench_function("CpuInfo::vendor_id", |b| b.iter(|| cpuinfo.vendor_id(0))); From 386b9952fbcc3d53f04b545fdaa1cc9a2ce398c5 Mon Sep 17 00:00:00 2001 From: Michael Schleicher Date: Mon, 28 Oct 2024 04:42:40 -0400 Subject: [PATCH 6/9] style: :art: fix format in different files --- procfs/benches/cpuinfo.rs | 4 +++- procfs/examples/lslocks.rs | 5 ++++- procfs/examples/mounts.rs | 4 ++-- procfs/src/crypto.rs | 6 ++---- procfs/src/sys/kernel/random.rs | 2 +- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/procfs/benches/cpuinfo.rs b/procfs/benches/cpuinfo.rs index 5cfd866..2c094d8 100644 --- a/procfs/benches/cpuinfo.rs +++ b/procfs/benches/cpuinfo.rs @@ -3,7 +3,9 @@ use procfs::CpuInfo; use procfs::Current; fn bench_cpuinfo(c: &mut Criterion) { - c.bench_function("CpuInfo::current", |b| b.iter(|| black_box(CpuInfo::current().unwrap()))); + c.bench_function("CpuInfo::current", |b| { + b.iter(|| black_box(CpuInfo::current().unwrap())) + }); let cpuinfo = black_box(CpuInfo::current().unwrap()); c.bench_function("CpuInfo::get_info", |b| b.iter(|| black_box(cpuinfo.get_info(0)))); diff --git a/procfs/examples/lslocks.rs b/procfs/examples/lslocks.rs index 622ec06..ecf43c1 100644 --- a/procfs/examples/lslocks.rs +++ b/procfs/examples/lslocks.rs @@ -5,7 +5,10 @@ use std::path::Path; fn main() { let myself = Process::myself().unwrap(); let mountinfo = myself.mountinfo().unwrap(); - println!("{:18}{:13}{:13}{:13}{:12} Path", "Process", "PID", "Lock Type", "Mode", "Kind"); + println!( + "{:18}{:13}{:13}{:13}{:12} Path", + "Process", "PID", "Lock Type", "Mode", "Kind" + ); println!("{}", "=".repeat(74)); for lock in procfs::locks().unwrap() { lock.pid diff --git a/procfs/examples/mounts.rs b/procfs/examples/mounts.rs index 71cebcc..2fb3191 100644 --- a/procfs/examples/mounts.rs +++ b/procfs/examples/mounts.rs @@ -1,11 +1,11 @@ // List mountpoints listed in /proc/mounts fn main() { -let width = 15; + let width = 15; for mount_entry in procfs::mounts().unwrap() { println!("Device: {}", mount_entry.fs_spec); println!("{:>width$}: {}", "Mount point", mount_entry.fs_file); - println!("{:>width$}: {}","FS type", mount_entry.fs_vfstype); + println!("{:>width$}: {}", "FS type", mount_entry.fs_vfstype); println!("{:>width$}: {}", "Dump", mount_entry.fs_freq); println!("{:>width$}: {}", "Check", mount_entry.fs_passno); print!("{:>width$}: ", "Options"); diff --git a/procfs/src/crypto.rs b/procfs/src/crypto.rs index d552484..6086d8f 100644 --- a/procfs/src/crypto.rs +++ b/procfs/src/crypto.rs @@ -1,6 +1,5 @@ - -use procfs_core::ProcResult; pub use procfs_core::CryptoTable; +use procfs_core::ProcResult; use crate::Current; @@ -12,7 +11,6 @@ pub fn crypto() -> ProcResult { CryptoTable::current() } - #[cfg(test)] mod tests { use super::*; @@ -23,4 +21,4 @@ mod tests { let table = table.expect("CrytoTable should have been read"); assert!(!table.crypto_blocks.is_empty(), "Crypto table was empty"); } -} \ No newline at end of file +} diff --git a/procfs/src/sys/kernel/random.rs b/procfs/src/sys/kernel/random.rs index 5c33a38..4f343cb 100644 --- a/procfs/src/sys/kernel/random.rs +++ b/procfs/src/sys/kernel/random.rs @@ -5,7 +5,7 @@ use crate::{read_value, write_value, ProcError, ProcResult}; use std::path::Path; -const RANDOM_ROOT: &str = "/proc/sys/kernel/random"; +const RANDOM_ROOT: &str = "/proc/sys/kernel/random"; /// This read-only file gives the available entropy, in bits. This will be a number in the range /// 0 to 4096 From ba0e2abeb229fd2085811539b4ad5d86f2a3aa5c Mon Sep 17 00:00:00 2001 From: Michael Schleicher Date: Mon, 28 Oct 2024 04:43:12 -0400 Subject: [PATCH 7/9] refactor: :fire: remove unnecessary pub use From f2dd881d11cb0c8f2e08181ba3e329a8c190ca1a Mon Sep 17 00:00:00 2001 From: Michael Schleicher Date: Mon, 28 Oct 2024 04:43:42 -0400 Subject: [PATCH 8/9] feat: :sparkles: implement serde for KernelVersion --- procfs-core/Cargo.toml | 10 ++++++-- procfs-core/src/lib.rs | 1 - procfs-core/src/sys/kernel/mod.rs | 41 ++++++++++++++++++++++++++++--- 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/procfs-core/Cargo.toml b/procfs-core/Cargo.toml index fdb5f06..49dc11d 100644 --- a/procfs-core/Cargo.toml +++ b/procfs-core/Cargo.toml @@ -14,14 +14,20 @@ rust-version.workspace = true [features] default = ["chrono"] -serde1 = ["serde", "bitflags/serde"] +serde1 = ["serde", "bitflags/serde", "serde_with"] [dependencies] backtrace = { version = "0.3", optional = true } bitflags = { version = "2" } -chrono = { version = "0.4.20", optional = true, features = ["clock"], default-features = false } +chrono = { version = "0.4.20", optional = true, features = [ + "clock", +], default-features = false } hex = "0.4" serde = { version = "1.0", features = ["derive"], optional = true } +serde_with = { version = "3.11", optional = true } + +[dev-dependencies] +serde_json = { version = "1.0" } [package.metadata.docs.rs] all-features = true diff --git a/procfs-core/src/lib.rs b/procfs-core/src/lib.rs index 256d3c7..769ad13 100644 --- a/procfs-core/src/lib.rs +++ b/procfs-core/src/lib.rs @@ -276,7 +276,6 @@ pub struct ExplicitSystemInfo { pub ticks_per_second: u64, pub page_size: u64, pub is_little_endian: bool, - #[cfg_attr(feature = "serde1", serde(skip))] pub kernel_version: KernelVersion, } diff --git a/procfs-core/src/sys/kernel/mod.rs b/procfs-core/src/sys/kernel/mod.rs index e3953e8..88c85a9 100644 --- a/procfs-core/src/sys/kernel/mod.rs +++ b/procfs-core/src/sys/kernel/mod.rs @@ -3,12 +3,12 @@ //! The files in this directory can be used to tune and monitor miscellaneous //! and general things in the operation of the Linux kernel. -use std::cmp; use std::collections::HashSet; use std::str::FromStr; +use std::{cmp, fmt::Display}; #[cfg(feature = "serde1")] -use serde::{Deserialize, Serialize}; +use serde_with::{DeserializeFromStr, SerializeDisplay}; use bitflags::bitflags; @@ -16,7 +16,7 @@ use crate::{ProcError, ProcResult}; /// Represents a kernel version, in major.minor.release version. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Default)] -#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde1", derive(SerializeDisplay, DeserializeFromStr))] pub struct Version { pub major: u8, pub minor: u8, @@ -103,6 +103,12 @@ impl cmp::PartialOrd for Version { } } +impl Display for Version { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}.{}.{}", self.major, self.minor, self.patch) + } +} + /// Represents a kernel type #[derive(Debug, Clone, Eq, PartialEq)] pub struct Type { @@ -429,4 +435,33 @@ mod tests { let a = SemaphoreLimits::from_str("1 string 500 3200"); assert!(a.is_err() && a.err().unwrap() == "Failed to parse SEMMNS"); } + + #[cfg(feature = "serde1")] + mod serde_kernel_version { + #[test] + fn should_serialize_kernel_version() { + let version = Version { + major: 42, + minor: 0, + patch: 1, + }; + let version = serde_json::to_string(&version).unwrap(); + + // NOTE: The double quote is necessary because of the JSON format. + assert_eq!(r#""42.0.1""#, &version); + } + + #[test] + fn should_deserialize_kernel_version() { + let expected = Version { + major: 21, + minor: 0, + patch: 2, + }; + // NOTE: The double quote is necessary because of the JSON format. + let version: Version = serde_json::from_str(r#""21.0.2""#).unwrap(); + + assert_eq!(version, expected); + } + } } From 13c79a8f0c609787fd64aa23fef594ee94e46047 Mon Sep 17 00:00:00 2001 From: Michael Schleicher Date: Mon, 28 Oct 2024 05:27:33 -0400 Subject: [PATCH 9/9] docs: :adhesive_bandage: update doc tests to include kernel version --- procfs-core/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/procfs-core/src/lib.rs b/procfs-core/src/lib.rs index 769ad13..9d6c1f4 100644 --- a/procfs-core/src/lib.rs +++ b/procfs-core/src/lib.rs @@ -245,6 +245,7 @@ macro_rules! from_str { /// ticks_per_second: 100, /// page_size: 4096, /// is_little_endian: true, +/// kernel_version: "6.11.0".parse().unwrap(), /// }; /// /// let rss_bytes = stat.rss_bytes().with_system_info(&system_info);