1#![deny(warnings)]
15#![deny(clippy::all)]
16#![allow(non_camel_case_types, non_snake_case)]
17
18use libloading::{Library, Symbol};
19use std::ffi::{c_int, c_void};
20use std::os::raw::c_long;
21
22pub const CUFILEOP_BASE_ERR: i32 = 5000;
23pub const CU_FILE_SUCCESS: i32 = 0;
24pub const CU_FILE_DRIVER_NOT_INITIALIZED: i32 = CUFILEOP_BASE_ERR + 1;
25pub const CU_FILE_PLATFORM_NOT_SUPPORTED: i32 = CUFILEOP_BASE_ERR + 7;
26pub const CU_FILE_IO_NOT_SUPPORTED: i32 = CUFILEOP_BASE_ERR + 8;
27pub const CU_FILE_DEVICE_NOT_SUPPORTED: i32 = CUFILEOP_BASE_ERR + 9;
28
29pub const CU_FILE_HANDLE_TYPE_OPAQUE_FD: c_int = 1;
30
31pub type CUfileHandle_t = *mut c_void;
32pub type CUresult = c_int;
33pub type CUfileOpError = c_int;
34
35#[repr(C)]
36#[derive(Copy, Clone, Debug)]
37pub struct CUfileError_t {
38 pub err: CUfileOpError,
39 pub cu_err: CUresult,
40}
41
42#[repr(C)]
43pub struct CUfileDescrHandle {
44 pub fd: c_int,
45 _pad: [u8; 8 - core::mem::size_of::<c_int>()],
46}
47
48impl CUfileDescrHandle {
49 pub fn from_fd(fd: c_int) -> Self {
50 Self {
51 fd,
52 _pad: [0; 8 - core::mem::size_of::<c_int>()],
53 }
54 }
55}
56
57#[repr(C)]
58pub struct CUfileDescr_t {
59 pub type_: c_int,
60 pub handle: CUfileDescrHandle,
61 pub fs_ops: *const c_void,
62}
63
64pub type FnDriverOpen = unsafe extern "C" fn() -> CUfileError_t;
65pub type FnDriverClose = unsafe extern "C" fn() -> CUfileError_t;
66pub type FnHandleRegister =
67 unsafe extern "C" fn(*mut CUfileHandle_t, *mut CUfileDescr_t) -> CUfileError_t;
68pub type FnHandleDeregister = unsafe extern "C" fn(CUfileHandle_t);
69pub type FnBufRegister = unsafe extern "C" fn(*const c_void, libc::size_t, c_int) -> CUfileError_t;
70pub type FnBufDeregister = unsafe extern "C" fn(*const c_void) -> CUfileError_t;
71pub type FnRead = unsafe extern "C" fn(
72 CUfileHandle_t,
73 *mut c_void,
74 libc::size_t,
75 c_long,
76 c_long,
77) -> libc::ssize_t;
78pub type FnWrite = unsafe extern "C" fn(
79 CUfileHandle_t,
80 *const c_void,
81 libc::size_t,
82 c_long,
83 c_long,
84) -> libc::ssize_t;
85pub type FnGetVersion = unsafe extern "C" fn(*mut c_int) -> CUfileError_t;
86
87pub struct CuFile {
88 _lib: Library,
89 pub driver_open: FnDriverOpen,
90 pub driver_close: FnDriverClose,
91 pub handle_register: FnHandleRegister,
92 pub handle_deregister: FnHandleDeregister,
93 pub buf_register: FnBufRegister,
94 pub buf_deregister: FnBufDeregister,
95 pub read: FnRead,
96 pub write: FnWrite,
97 pub get_version: FnGetVersion,
98}
99
100const SEARCH_PATHS: &[&str] = &[
101 "libcufile.so.0",
102 "libcufile.so",
103 "/usr/local/cuda/targets/sbsa-linux/lib/libcufile.so.0",
104 "/usr/local/cuda/targets/x86_64-linux/lib/libcufile.so.0",
105 "/usr/local/cuda-13.0/targets/sbsa-linux/lib/libcufile.so.0",
106];
107
108impl CuFile {
109 pub fn load() -> Result<Self, String> {
110 let mut last_err = String::new();
111 for path in SEARCH_PATHS {
112 match unsafe { Library::new(path) } {
113 Ok(lib) => return Self::resolve(lib).map_err(|e| format!("{path}: {e}")),
114 Err(e) => last_err = format!("{path}: {e}"),
115 }
116 }
117 Err(format!("libcufile not found ({last_err})"))
118 }
119
120 fn resolve(lib: Library) -> Result<Self, String> {
121 unsafe fn sym<'a, T: Copy + 'a>(lib: &'a Library, name: &[u8]) -> Result<T, String> {
122 unsafe {
123 let s: Symbol<'a, T> = lib
124 .get(name)
125 .map_err(|e| format!("symbol {}: {e}", String::from_utf8_lossy(name)))?;
126 Ok(*s)
127 }
128 }
129 unsafe {
130 let driver_open = sym::<FnDriverOpen>(&lib, b"cuFileDriverOpen\0")?;
131 let driver_close = sym::<FnDriverClose>(&lib, b"cuFileDriverClose\0")?;
132 let handle_register = sym::<FnHandleRegister>(&lib, b"cuFileHandleRegister\0")?;
133 let handle_deregister = sym::<FnHandleDeregister>(&lib, b"cuFileHandleDeregister\0")?;
134 let buf_register = sym::<FnBufRegister>(&lib, b"cuFileBufRegister\0")?;
135 let buf_deregister = sym::<FnBufDeregister>(&lib, b"cuFileBufDeregister\0")?;
136 let read = sym::<FnRead>(&lib, b"cuFileRead\0")?;
137 let write = sym::<FnWrite>(&lib, b"cuFileWrite\0")?;
138 let get_version = sym::<FnGetVersion>(&lib, b"cuFileGetVersion\0")?;
139 Ok(Self {
140 _lib: lib,
141 driver_open,
142 driver_close,
143 handle_register,
144 handle_deregister,
145 buf_register,
146 buf_deregister,
147 read,
148 write,
149 get_version,
150 })
151 }
152 }
153}
154
155pub fn err_to_str(err: CUfileOpError) -> &'static str {
156 match err {
157 0 => "success",
158 x if x == CU_FILE_DRIVER_NOT_INITIALIZED => "CU_FILE_DRIVER_NOT_INITIALIZED",
159 x if x == CU_FILE_PLATFORM_NOT_SUPPORTED => "CU_FILE_PLATFORM_NOT_SUPPORTED",
160 x if x == CU_FILE_IO_NOT_SUPPORTED => "CU_FILE_IO_NOT_SUPPORTED",
161 x if x == CU_FILE_DEVICE_NOT_SUPPORTED => "CU_FILE_DEVICE_NOT_SUPPORTED",
162 _ => "CU_FILE_OTHER_ERROR",
163 }
164}
165
166pub fn nvidia_fs_loaded() -> bool {
167 let modules = match std::fs::read_to_string("/proc/modules") {
168 Ok(s) => s,
169 Err(_) => return false,
170 };
171 modules
172 .lines()
173 .any(|l| l.starts_with("nvidia_fs ") || l.starts_with("nvidia-fs "))
174}