1use super::{MemoryDescriptor, Result, StorageError, StorageKind, actions, nixl::NixlDescriptor};
7use std::any::Any;
8use std::ptr::NonNull;
9
10#[derive(Debug)]
12pub struct SystemStorage {
13 ptr: NonNull<u8>,
14 len: usize,
15}
16
17unsafe impl Send for SystemStorage {}
18unsafe impl Sync for SystemStorage {}
19
20impl SystemStorage {
21 pub fn new(len: usize) -> Result<Self> {
23 if len == 0 {
24 return Err(StorageError::AllocationFailed(
25 "zero-sized allocations are not supported".into(),
26 ));
27 }
28
29 let mut ptr: *mut libc::c_void = std::ptr::null_mut();
30
31 let result = unsafe { libc::posix_memalign(&mut ptr, 4096, len) };
40 if result != 0 {
41 return Err(StorageError::AllocationFailed(format!(
42 "posix_memalign failed for size {}",
43 len
44 )));
45 }
46 let ptr = NonNull::new(ptr as *mut u8).ok_or_else(|| {
47 StorageError::AllocationFailed(format!("malloc failed for size {}", len))
48 })?;
49
50 unsafe {
52 std::ptr::write_bytes(ptr.as_ptr(), 0, len);
53 }
54
55 Ok(Self { ptr, len })
56 }
57
58 pub unsafe fn as_ptr(&self) -> *const u8 {
63 self.ptr.as_ptr()
64 }
65
66 pub unsafe fn as_mut_ptr(&mut self) -> *mut u8 {
72 self.ptr.as_ptr()
73 }
74}
75
76impl Drop for SystemStorage {
77 fn drop(&mut self) {
78 unsafe {
80 libc::free(self.ptr.as_ptr() as *mut libc::c_void);
81 }
82 }
83}
84
85impl MemoryDescriptor for SystemStorage {
86 fn addr(&self) -> usize {
87 self.ptr.as_ptr() as usize
88 }
89
90 fn size(&self) -> usize {
91 self.len
92 }
93
94 fn storage_kind(&self) -> StorageKind {
95 StorageKind::System
96 }
97
98 fn as_any(&self) -> &dyn Any {
99 self
100 }
101
102 fn nixl_descriptor(&self) -> Option<NixlDescriptor> {
103 None
104 }
105}
106
107impl super::nixl::NixlCompatible for SystemStorage {
109 fn nixl_params(&self) -> (*const u8, usize, nixl_sys::MemType, u64) {
110 (self.ptr.as_ptr(), self.len, nixl_sys::MemType::Dram, 0)
111 }
112}
113
114impl actions::Memset for SystemStorage {
115 fn memset(&mut self, value: u8, offset: usize, size: usize) -> Result<()> {
116 let end = offset
117 .checked_add(size)
118 .ok_or_else(|| StorageError::OperationFailed("memset: offset overflow".into()))?;
119 if end > self.len {
120 return Err(StorageError::OperationFailed(
121 "memset: offset + size > storage size".into(),
122 ));
123 }
124 unsafe {
125 let ptr = self.ptr.as_ptr().add(offset);
126 std::ptr::write_bytes(ptr, value, size);
127 }
128 Ok(())
129 }
130}
131
132impl actions::Slice for SystemStorage {
133 unsafe fn as_slice(&self) -> Result<&[u8]> {
134 Ok(unsafe { std::slice::from_raw_parts(self.ptr.as_ptr(), self.len) })
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146 use crate::actions::{Memset, Slice};
147
148 #[test]
149 fn test_system_storage_new() {
150 let storage = SystemStorage::new(1024).expect("allocation should succeed");
151 assert_eq!(storage.size(), 1024);
152 assert!(storage.addr() != 0);
153 }
154
155 #[test]
156 fn test_system_storage_zero_size_fails() {
157 let result = SystemStorage::new(0);
158 assert!(result.is_err());
159 }
160
161 #[test]
162 fn test_system_storage_storage_kind() {
163 let storage = SystemStorage::new(1024).unwrap();
164 assert_eq!(storage.storage_kind(), StorageKind::System);
165 }
166
167 #[test]
168 fn test_system_storage_as_any() {
169 let storage = SystemStorage::new(1024).unwrap();
170 let any = storage.as_any();
171 assert!(any.downcast_ref::<SystemStorage>().is_some());
172 }
173
174 #[test]
175 fn test_system_storage_nixl_descriptor() {
176 let storage = SystemStorage::new(1024).unwrap();
177 assert!(storage.nixl_descriptor().is_none());
179 }
180
181 #[test]
182 fn test_system_storage_as_ptr() {
183 let storage = SystemStorage::new(1024).unwrap();
184 unsafe {
185 let ptr = storage.as_ptr();
186 assert!(!ptr.is_null());
187 assert_eq!(ptr as usize, storage.addr());
188 }
189 }
190
191 #[test]
192 fn test_system_storage_as_mut_ptr() {
193 let mut storage = SystemStorage::new(1024).unwrap();
194 unsafe {
195 let ptr = storage.as_mut_ptr();
196 assert!(!ptr.is_null());
197 assert_eq!(ptr as usize, storage.addr());
198
199 *ptr = 0xAB;
201 assert_eq!(*ptr, 0xAB);
202 }
203 }
204
205 #[test]
206 fn test_system_storage_zero_initialized() {
207 let storage = SystemStorage::new(1024).unwrap();
208 unsafe {
209 let slice = storage.as_slice().unwrap();
210 assert!(slice.iter().all(|&b| b == 0));
212 }
213 }
214
215 #[test]
216 fn test_system_storage_memset_and_read() {
217 let mut storage = SystemStorage::new(1024).unwrap();
218 storage.memset(0xCD, 0, 1024).unwrap();
219
220 unsafe {
221 let slice = storage.as_slice().unwrap();
222 assert!(slice.iter().all(|&b| b == 0xCD));
223 }
224 }
225
226 #[test]
227 fn test_system_storage_multiple_allocations_independent() {
228 let storage1 = SystemStorage::new(512).unwrap();
229 let storage2 = SystemStorage::new(512).unwrap();
230
231 assert_ne!(storage1.addr(), storage2.addr());
233 }
234
235 #[test]
236 fn test_system_storage_alignment() {
237 let storage = SystemStorage::new(1024).unwrap();
238 assert!(storage.addr().is_multiple_of(4096));
240 }
241
242 #[test]
243 fn test_system_storage_nixl_compatible() {
244 use crate::nixl::NixlCompatible;
245
246 let storage = SystemStorage::new(2048).unwrap();
247 let (ptr, size, mem_type, device_id) = storage.nixl_params();
248
249 assert_eq!(ptr as usize, storage.addr());
250 assert_eq!(size, 2048);
251 assert_eq!(mem_type, nixl_sys::MemType::Dram);
252 assert_eq!(device_id, 0);
253 }
254
255 #[test]
256 fn test_system_storage_large_allocation() {
257 let storage = SystemStorage::new(1024 * 1024).unwrap();
259 assert_eq!(storage.size(), 1024 * 1024);
260 }
261
262 #[test]
263 fn test_system_storage_debug() {
264 let storage = SystemStorage::new(1024).unwrap();
265 let debug_str = format!("{:?}", storage);
266 assert!(debug_str.contains("SystemStorage"));
267 }
268}