1use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use std::fs::OpenOptions;
9use std::path::Path;
10
11pub struct ZnsZoneManager {
13 zones: Vec<ZnsZone>,
14 allocator: ZoneAllocator,
15 io_scheduler: ZnsIoScheduler,
16 device_info: ZnsDeviceInfo,
17}
18
19#[derive(Debug, Clone)]
21pub struct ZnsZone {
22 pub zone_id: u32,
23 pub zone_type: ZoneType,
24 pub capacity: u64,
25 pub write_pointer: u64,
26 pub state: ZoneState,
27 pub zone_start_lba: u64,
28 pub zone_size: u64,
29}
30
31#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
33pub enum ZoneType {
34 Sequential,
36 Random,
38 Computational,
40}
41
42#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
44pub enum ZoneState {
45 Empty,
46 ImplicitlyOpened,
47 ExplicitlyOpened,
48 Closed,
49 Full,
50 ReadOnly,
51 Offline,
52}
53
54#[derive(Debug, Clone)]
56pub struct ZnsDeviceInfo {
57 pub device_id: String,
58 pub total_zones: u32,
59 pub zone_size: u64,
60 pub sector_size: u32,
61 pub max_open_zones: u32,
62 pub optimal_open_zones: u32,
63}
64
65pub struct ZoneAllocator {
67 free_zones: Vec<u32>,
68 allocated_zones: HashMap<u32, ZoneHandle>,
69 allocation_strategy: AllocationStrategy,
70}
71
72#[derive(Debug, Clone)]
74pub enum AllocationStrategy {
75 RoundRobin,
77 Sequential,
79 WorkloadAware,
81}
82
83#[derive(Debug, Clone)]
85pub struct ZoneHandle {
86 pub zone_id: u32,
87 pub zone_type: ZoneType,
88 pub offset: u64,
89 pub size: u64,
90}
91
92pub struct ZnsIoScheduler {
94 pending_operations: Vec<ZnsOperation>,
95 completion_queue: Vec<ZnsCompletion>,
96 scheduler_policy: SchedulerPolicy,
97}
98
99#[derive(Debug, Clone)]
101pub enum ZnsOperation {
102 Write {
103 zone_id: u32,
104 lba: u64,
105 data: Vec<u8>,
106 operation_id: u64,
107 },
108 Read {
109 zone_id: u32,
110 lba: u64,
111 length: u64,
112 operation_id: u64,
113 },
114 Flush {
115 zone_id: u32,
116 operation_id: u64,
117 },
118 Reset {
119 zone_id: u32,
120 operation_id: u64,
121 },
122}
123
124#[derive(Debug, Clone)]
126pub struct ZnsCompletion {
127 pub operation_id: u64,
128 pub status: CompletionStatus,
129 pub bytes_transferred: u64,
130}
131
132#[derive(Debug, Clone, PartialEq)]
134pub enum CompletionStatus {
135 Success,
136 Error(String),
137 Timeout,
138}
139
140#[derive(Debug, Clone)]
142pub enum SchedulerPolicy {
143 Fifo,
145 Priority,
147 Deadline,
149}
150
151pub struct ZeroCopyBuffer {
153 pub ptr: *mut u8,
154 pub size: usize,
155 pub capacity: usize,
156}
157
158impl ZnsZoneManager {
159 pub fn new<P: AsRef<Path>>(device_path: P) -> Result<Self, ZnsError> {
161 let device_info = Self::probe_device(&device_path)?;
162 let zones = Self::initialize_zones(&device_info)?;
163 let allocator = ZoneAllocator::new(device_info.total_zones);
164 let io_scheduler = ZnsIoScheduler::new();
165
166 Ok(Self {
167 zones,
168 allocator,
169 io_scheduler,
170 device_info,
171 })
172 }
173
174 fn probe_device<P: AsRef<Path>>(device_path: P) -> Result<ZnsDeviceInfo, ZnsError> {
176 let device_path = device_path.as_ref();
177
178 let _device_file = OpenOptions::new()
180 .read(true)
181 .write(true)
182 .open(device_path)
183 .map_err(|e| ZnsError::DeviceOpen(e.to_string()))?;
184
185 let device_id = format!("zns-{}", device_path.display());
187
188 let device_info = ZnsDeviceInfo {
190 device_id,
191 total_zones: 1024,
192 zone_size: 256 * 1024 * 1024, sector_size: 4096,
194 max_open_zones: 64,
195 optimal_open_zones: 32,
196 };
197
198 Ok(device_info)
199 }
200
201 fn initialize_zones(device_info: &ZnsDeviceInfo) -> Result<Vec<ZnsZone>, ZnsError> {
203 let mut zones = Vec::new();
204
205 for zone_id in 0..device_info.total_zones {
206 let zone = ZnsZone {
207 zone_id,
208 zone_type: if zone_id < device_info.total_zones / 2 {
209 ZoneType::Sequential
210 } else if zone_id < device_info.total_zones * 3 / 4 {
211 ZoneType::Random
212 } else {
213 ZoneType::Computational
214 },
215 capacity: device_info.zone_size,
216 write_pointer: 0,
217 state: ZoneState::Empty,
218 zone_start_lba: zone_id as u64 * device_info.zone_size
219 / device_info.sector_size as u64,
220 zone_size: device_info.zone_size,
221 };
222 zones.push(zone);
223 }
224
225 Ok(zones)
226 }
227
228 pub fn allocate_zone(
230 &mut self,
231 zone_type: ZoneType,
232 size: u64,
233 ) -> Result<ZoneHandle, ZnsError> {
234 let zone_id = self.allocator.allocate_zone(zone_type.clone())?;
235 let zone = &mut self.zones[zone_id as usize];
236
237 zone.state = ZoneState::ExplicitlyOpened;
239 zone.write_pointer = 0;
240
241 Ok(ZoneHandle {
242 zone_id,
243 zone_type,
244 offset: 0,
245 size,
246 })
247 }
248
249 pub fn write_zone(&mut self, handle: &ZoneHandle, data: &[u8]) -> Result<(), ZnsError> {
251 let op_id = self.generate_operation_id();
252
253 let zone = &mut self.zones[handle.zone_id as usize];
254
255 if zone.state != ZoneState::ExplicitlyOpened && zone.state != ZoneState::ImplicitlyOpened {
257 return Err(ZnsError::InvalidZoneState(format!(
258 "Zone {} is not open for writing",
259 handle.zone_id
260 )));
261 }
262
263 let write_position = zone.write_pointer;
265 if write_position + data.len() as u64 > zone.capacity {
266 return Err(ZnsError::ZoneFull(format!(
267 "Zone {} is full",
268 handle.zone_id
269 )));
270 }
271
272 let lba = zone.zone_start_lba + write_position / zone.zone_size * zone.zone_size / 4096;
274
275 let operation = ZnsOperation::Write {
277 zone_id: handle.zone_id,
278 lba,
279 data: data.to_vec(),
280 operation_id: op_id,
281 };
282
283 self.io_scheduler.schedule_operation(operation);
284
285 zone.write_pointer += data.len() as u64;
287
288 if zone.write_pointer >= zone.capacity {
290 zone.state = ZoneState::Full;
291 self.flush_zone(handle)?;
292 }
293
294 Ok(())
295 }
296
297 pub fn read_zone(
299 &mut self,
300 handle: &ZoneHandle,
301 offset: u64,
302 length: u64,
303 ) -> Result<Vec<u8>, ZnsError> {
304 let op_id = self.generate_operation_id();
305
306 let zone = &self.zones[handle.zone_id as usize];
307
308 if offset + length > zone.write_pointer {
310 return Err(ZnsError::InvalidOffset(format!(
311 "Read beyond write pointer in zone {}",
312 handle.zone_id
313 )));
314 }
315
316 let lba = zone.zone_start_lba + offset / 4096;
318
319 let operation = ZnsOperation::Read {
321 zone_id: handle.zone_id,
322 lba,
323 length,
324 operation_id: op_id,
325 };
326
327 self.io_scheduler.schedule_operation(operation);
328
329 let _zc = self.zero_copy_access(handle)?;
330 Ok(vec![0u8; length as usize])
332 }
333
334 pub fn zero_copy_access(&self, handle: &ZoneHandle) -> Result<ZeroCopyBuffer, ZnsError> {
336 let zone = &self.zones[handle.zone_id as usize];
337
338 let buffer = ZeroCopyBuffer {
340 ptr: std::ptr::null_mut(), size: handle.size as usize,
342 capacity: zone.capacity as usize,
343 };
344
345 Ok(buffer)
346 }
347
348 pub fn flush_zone(&mut self, handle: &ZoneHandle) -> Result<(), ZnsError> {
350 let op_id = self.generate_operation_id();
351
352 let zone = &mut self.zones[handle.zone_id as usize];
353
354 let operation = ZnsOperation::Flush {
356 zone_id: handle.zone_id,
357 operation_id: op_id,
358 };
359
360 self.io_scheduler.schedule_operation(operation);
361
362 if zone.state == ZoneState::Full {
364 zone.state = ZoneState::Closed;
365 }
366
367 Ok(())
368 }
369
370 pub fn reset_zone(&mut self, handle: &ZoneHandle) -> Result<(), ZnsError> {
372 let op_id = self.generate_operation_id();
373
374 let zone = &mut self.zones[handle.zone_id as usize];
375
376 let operation = ZnsOperation::Reset {
378 zone_id: handle.zone_id,
379 operation_id: op_id,
380 };
381
382 self.io_scheduler.schedule_operation(operation);
383
384 zone.state = ZoneState::Empty;
386 zone.write_pointer = 0;
387
388 self.allocator.deallocate_zone(handle.zone_id);
390
391 Ok(())
392 }
393
394 pub fn get_zone_stats(&self, zone_id: u32) -> Result<ZoneStats, ZnsError> {
396 let zone = &self.zones[zone_id as usize];
397
398 Ok(ZoneStats {
399 zone_id: zone.zone_id,
400 zone_type: zone.zone_type.clone(),
401 capacity: zone.capacity,
402 used_space: zone.write_pointer,
403 free_space: zone.capacity - zone.write_pointer,
404 state: zone.state.clone(),
405 })
406 }
407
408 pub fn get_device_stats(&self) -> DeviceStats {
410 let mut total_used = 0u64;
411 let mut total_free = 0u64;
412 let mut open_zones = 0u32;
413 let mut full_zones = 0u32;
414
415 for zone in &self.zones {
416 total_used += zone.write_pointer;
417 total_free += zone.capacity - zone.write_pointer;
418
419 match zone.state {
420 ZoneState::ExplicitlyOpened | ZoneState::ImplicitlyOpened => open_zones += 1,
421 ZoneState::Full => full_zones += 1,
422 _ => {}
423 }
424 }
425
426 DeviceStats {
427 total_zones: self.device_info.total_zones,
428 open_zones,
429 full_zones,
430 total_capacity: self.device_info.total_zones as u64 * self.device_info.zone_size,
431 used_capacity: total_used,
432 free_capacity: total_free,
433 }
434 }
435
436 fn generate_operation_id(&self) -> u64 {
438 use std::sync::atomic::{AtomicU64, Ordering};
439 static COUNTER: AtomicU64 = AtomicU64::new(1);
440 COUNTER.fetch_add(1, Ordering::SeqCst)
441 }
442}
443
444impl ZoneAllocator {
445 pub fn new(total_zones: u32) -> Self {
447 let free_zones = (0..total_zones).collect();
448 let allocated_zones = HashMap::new();
449 let allocation_strategy = AllocationStrategy::WorkloadAware;
450
451 Self {
452 free_zones,
453 allocated_zones,
454 allocation_strategy,
455 }
456 }
457
458 pub fn allocation_strategy(&self) -> &AllocationStrategy {
460 &self.allocation_strategy
461 }
462
463 pub fn allocate_zone(&mut self, zone_type: ZoneType) -> Result<u32, ZnsError> {
465 let zone_id = match self.allocation_strategy {
466 AllocationStrategy::Sequential => {
467 if self.free_zones.is_empty() {
468 None
469 } else {
470 Some(self.free_zones.remove(0))
471 }
472 }
473 AllocationStrategy::RoundRobin | AllocationStrategy::WorkloadAware => {
474 self.free_zones.pop()
475 }
476 }
477 .ok_or_else(|| ZnsError::NoZonesAvailable("No free zones available".to_string()))?;
478
479 let handle = ZoneHandle {
480 zone_id,
481 zone_type: zone_type.clone(),
482 offset: 0,
483 size: 0, };
485
486 self.allocated_zones.insert(zone_id, handle);
487 Ok(zone_id)
488 }
489
490 pub fn deallocate_zone(&mut self, zone_id: u32) {
492 self.allocated_zones.remove(&zone_id);
493 self.free_zones.push(zone_id);
494 }
495}
496
497impl ZnsIoScheduler {
498 pub fn new() -> Self {
500 Self {
501 pending_operations: Vec::new(),
502 completion_queue: Vec::new(),
503 scheduler_policy: SchedulerPolicy::Priority,
504 }
505 }
506
507 pub fn schedule_operation(&mut self, operation: ZnsOperation) {
509 self.pending_operations.push(operation);
510 }
511
512 pub fn scheduler_policy(&self) -> &SchedulerPolicy {
514 &self.scheduler_policy
515 }
516
517 pub fn drain_completions(&mut self) -> Vec<ZnsCompletion> {
519 std::mem::take(&mut self.completion_queue)
520 }
521
522 pub fn process_operations(&mut self) -> Vec<ZnsCompletion> {
524 match self.scheduler_policy {
525 SchedulerPolicy::Priority => {
526 self.pending_operations.sort_by_key(|op| match op {
527 ZnsOperation::Write { operation_id, .. }
528 | ZnsOperation::Read { operation_id, .. }
529 | ZnsOperation::Flush { operation_id, .. }
530 | ZnsOperation::Reset { operation_id, .. } => *operation_id,
531 });
532 }
533 SchedulerPolicy::Fifo | SchedulerPolicy::Deadline => {}
534 }
535
536 let mut completions = Vec::new();
537
538 while let Some(operation) = self.pending_operations.pop() {
539 let completion = match operation {
540 ZnsOperation::Write { operation_id, .. } => ZnsCompletion {
541 operation_id,
542 status: CompletionStatus::Success,
543 bytes_transferred: 4096,
544 },
545 ZnsOperation::Read {
546 operation_id,
547 length,
548 ..
549 } => ZnsCompletion {
550 operation_id,
551 status: CompletionStatus::Success,
552 bytes_transferred: length,
553 },
554 ZnsOperation::Flush { operation_id, .. } => ZnsCompletion {
555 operation_id,
556 status: CompletionStatus::Success,
557 bytes_transferred: 0,
558 },
559 ZnsOperation::Reset { operation_id, .. } => ZnsCompletion {
560 operation_id,
561 status: CompletionStatus::Success,
562 bytes_transferred: 0,
563 },
564 };
565
566 completions.push(completion.clone());
567 self.completion_queue.push(completion);
568 }
569
570 completions
571 }
572}
573
574#[derive(Debug, Clone)]
576pub struct ZoneStats {
577 pub zone_id: u32,
578 pub zone_type: ZoneType,
579 pub capacity: u64,
580 pub used_space: u64,
581 pub free_space: u64,
582 pub state: ZoneState,
583}
584
585#[derive(Debug, Clone)]
587pub struct DeviceStats {
588 pub total_zones: u32,
589 pub open_zones: u32,
590 pub full_zones: u32,
591 pub total_capacity: u64,
592 pub used_capacity: u64,
593 pub free_capacity: u64,
594}
595
596#[derive(Debug, Clone)]
598pub enum ZnsError {
599 DeviceOpen(String),
600 InvalidZoneState(String),
601 ZoneFull(String),
602 InvalidOffset(String),
603 NoZonesAvailable(String),
604 IoError(String),
605 ConfigurationError(String),
606}
607
608impl std::fmt::Display for ZnsError {
609 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
610 match self {
611 ZnsError::DeviceOpen(msg) => write!(f, "Device open error: {}", msg),
612 ZnsError::InvalidZoneState(msg) => write!(f, "Invalid zone state: {}", msg),
613 ZnsError::ZoneFull(msg) => write!(f, "Zone full: {}", msg),
614 ZnsError::InvalidOffset(msg) => write!(f, "Invalid offset: {}", msg),
615 ZnsError::NoZonesAvailable(msg) => write!(f, "No zones available: {}", msg),
616 ZnsError::IoError(msg) => write!(f, "I/O error: {}", msg),
617 ZnsError::ConfigurationError(msg) => write!(f, "Configuration error: {}", msg),
618 }
619 }
620}
621
622impl std::error::Error for ZnsError {}
623
624unsafe impl Send for ZeroCopyBuffer {}
626unsafe impl Sync for ZeroCopyBuffer {}
627
628#[cfg(test)]
629mod tests {
630 use super::*;
631
632 #[test]
633 fn test_zone_allocation() {
634 let mut allocator = ZoneAllocator::new(1024);
635
636 let zone_id = allocator.allocate_zone(ZoneType::Sequential).unwrap();
638 assert!(zone_id < 1024);
639
640 allocator.deallocate_zone(zone_id);
642
643 let zone_id2 = allocator.allocate_zone(ZoneType::Sequential).unwrap();
645 assert!(zone_id2 < 1024);
646 }
647
648 #[test]
649 fn test_zone_stats() {
650 let zone = ZnsZone {
651 zone_id: 0,
652 zone_type: ZoneType::Sequential,
653 capacity: 1024 * 1024,
654 write_pointer: 512 * 1024,
655 state: ZoneState::ExplicitlyOpened,
656 zone_start_lba: 0,
657 zone_size: 1024 * 1024,
658 };
659
660 let stats = ZoneStats {
661 zone_id: zone.zone_id,
662 zone_type: zone.zone_type.clone(),
663 capacity: zone.capacity,
664 used_space: zone.write_pointer,
665 free_space: zone.capacity - zone.write_pointer,
666 state: zone.state.clone(),
667 };
668
669 assert_eq!(stats.zone_id, 0);
670 assert_eq!(stats.used_space, 512 * 1024);
671 assert_eq!(stats.free_space, 512 * 1024);
672 assert_eq!(stats.state, ZoneState::ExplicitlyOpened);
673 }
674
675 #[test]
676 fn test_io_scheduler() {
677 let mut scheduler = ZnsIoScheduler::new();
678
679 let write_op = ZnsOperation::Write {
681 zone_id: 0,
682 lba: 1000,
683 data: vec![1, 2, 3, 4],
684 operation_id: 1,
685 };
686
687 scheduler.schedule_operation(write_op);
688
689 let completions = scheduler.process_operations();
691 assert_eq!(completions.len(), 1);
692 assert_eq!(completions[0].operation_id, 1);
693 assert_eq!(completions[0].status, CompletionStatus::Success);
694 }
695}