vyre_runtime/uring/
gpudirect.rs1#[cfg(all(target_os = "linux", feature = "uring-cmd-nvme"))]
18use std::fs;
19#[cfg(all(target_os = "linux", feature = "uring-cmd-nvme"))]
20use std::io::{ErrorKind, Read as _};
21
22#[cfg(all(target_os = "linux", feature = "uring-cmd-nvme"))]
23const MAX_NVIDIA_FS_STATS_BYTES: u64 = 1024 * 1024;
24
25#[derive(Debug, Clone, PartialEq, Eq)]
27pub enum GpuDirectCapability {
28 Available {
31 stats: String,
35 },
36 Unavailable {
41 reason: &'static str,
43 },
44 FeatureDisabled,
48}
49
50impl GpuDirectCapability {
51 #[must_use]
58 pub fn probe() -> Self {
59 #[cfg(not(all(target_os = "linux", feature = "uring-cmd-nvme")))]
60 {
61 GpuDirectCapability::FeatureDisabled
62 }
63
64 #[cfg(all(target_os = "linux", feature = "uring-cmd-nvme"))]
65 match read_nvidia_fs_stats() {
66 Ok(stats) if !stats.trim().is_empty() => {
67 GpuDirectCapability::Available { stats }
68 }
69 Ok(_) => GpuDirectCapability::Unavailable {
70 reason: "nvidia-fs stats file is empty; driver reports no GPUDirect sessions",
71 },
72 Err(err) if err.kind() == ErrorKind::NotFound => GpuDirectCapability::Unavailable {
73 reason: "/proc/driver/nvidia-fs/stats not found; nvidia-fs is not installed",
74 },
75 Err(err) if err.kind() == ErrorKind::PermissionDenied => GpuDirectCapability::Unavailable {
76 reason: "/proc/driver/nvidia-fs/stats refused permission; run with adequate privileges",
77 },
78 Err(_) => GpuDirectCapability::Unavailable {
79 reason: "/proc/driver/nvidia-fs/stats read failed for an unexpected reason",
80 },
81 }
82 }
83
84 #[must_use]
87 pub fn is_available(&self) -> bool {
88 matches!(self, GpuDirectCapability::Available { .. })
89 }
90}
91
92#[cfg(all(target_os = "linux", feature = "uring-cmd-nvme"))]
93fn read_nvidia_fs_stats() -> std::io::Result<String> {
94 let mut file = fs::File::open("/proc/driver/nvidia-fs/stats")?;
95 let mut stats = String::new();
96 file.by_ref()
97 .take(MAX_NVIDIA_FS_STATS_BYTES + 1)
98 .read_to_string(&mut stats)?;
99 let stats_len = u64::try_from(stats.len()).map_err(|error| {
100 std::io::Error::new(
101 std::io::ErrorKind::InvalidData,
102 format!("nvidia-fs stats length cannot fit u64: {error}"),
103 )
104 })?;
105 if stats_len > MAX_NVIDIA_FS_STATS_BYTES {
106 return Err(std::io::Error::new(
107 std::io::ErrorKind::InvalidData,
108 "nvidia-fs stats exceeded bounded read limit",
109 ));
110 }
111 Ok(stats)
112}
113
114pub const NVME_CMD_READ: u8 = 0x02;
116
117#[must_use]
142pub fn encode_nvme_read_sqe(
143 namespace_id: u32,
144 starting_lba: u64,
145 blocks: u32,
146 dest_bar1_ptr: u64,
147) -> [u8; 64] {
148 assert!(
149 blocks > 0,
150 "NVMe read SQE cannot encode zero blocks; validate read length before submitting GPU-direct ingest"
151 );
152 let mut buf = [0u8; 64];
153 buf[0] = NVME_CMD_READ;
154 buf[4..8].copy_from_slice(&namespace_id.to_le_bytes());
155 buf[32..40].copy_from_slice(&dest_bar1_ptr.to_le_bytes());
156 buf[40..48].copy_from_slice(&starting_lba.to_le_bytes());
157 let zero_based = blocks - 1;
159 buf[48..52].copy_from_slice(&zero_based.to_le_bytes());
160 buf
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 #[test]
168 fn probe_returns_a_structured_variant() {
169 match GpuDirectCapability::probe() {
173 GpuDirectCapability::Available { .. } => {}
174 GpuDirectCapability::Unavailable { .. } => {}
175 GpuDirectCapability::FeatureDisabled => {}
176 }
177 }
178
179 #[test]
180 fn encode_nvme_read_sqe_layout_matches_spec() {
181 let sqe = encode_nvme_read_sqe(
182 1,
183 0x1122_3344_5566_7788,
184 8,
185 0xAABB_CCDD_EEFF_0011,
186 );
187 assert_eq!(sqe[0], NVME_CMD_READ);
188 assert_eq!(sqe[4..8], 1u32.to_le_bytes());
189 assert_eq!(sqe[32..40], 0xAABB_CCDD_EEFF_0011u64.to_le_bytes());
190 assert_eq!(sqe[40..48], 0x1122_3344_5566_7788u64.to_le_bytes());
191 assert_eq!(sqe[48..52], 7u32.to_le_bytes());
193 assert_eq!(&sqe[8..32], &[0u8; 24]);
195 assert_eq!(&sqe[52..64], &[0u8; 12]);
196 }
197
198 #[test]
199 fn encode_nvme_single_block_yields_zero_in_nblocks_field() {
200 let sqe = encode_nvme_read_sqe(1, 0, 1, 0);
202 assert_eq!(sqe[48..52], 0u32.to_le_bytes());
203 }
204
205 #[test]
206 fn is_available_reflects_variant() {
207 let available = GpuDirectCapability::Available {
208 stats: "session_count=1".into(),
209 };
210 assert!(available.is_available());
211 let unavail = GpuDirectCapability::Unavailable {
212 reason: "test reason",
213 };
214 assert!(!unavail.is_available());
215 assert!(!GpuDirectCapability::FeatureDisabled.is_available());
216 }
217}