1use crate::BLOCK_SIZE;
6use anyhow::{Error, anyhow};
7use std::ops::Range;
8
9const TYPE_MASK: u64 = 0xc0000000_00000000;
10const REGULAR: u64 = 0x00000000_00000000;
11const SPARSE: u64 = 0x80000000_00000000;
12
13const MAX_REGULAR_EXTENT_BLOCKS: u64 = 0x3fff_ffff;
19
20const MAX_SPARSE_EXTENT_BLOCKS: u64 = !TYPE_MASK;
22
23#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct Extent {
28 logical_range: Range<u64>,
29 device_offset: Option<u64>,
30}
31
32impl Extent {
33 pub fn logical_range(&self) -> Range<u64> {
35 self.logical_range.clone()
36 }
37
38 pub fn device_offset(&self) -> Option<u64> {
40 self.device_offset
41 }
42
43 pub fn is_sparse(&self) -> bool {
45 self.device_offset.is_none()
46 }
47
48 pub fn len(&self) -> u64 {
50 self.logical_range.end - self.logical_range.start
51 }
52
53 pub fn new(logical_range: Range<u64>, device_offset: Option<u64>) -> Self {
61 Self::try_new(logical_range, device_offset).unwrap()
62 }
63
64 pub fn try_new(logical_range: Range<u64>, device_offset: Option<u64>) -> Result<Self, Error> {
66 if logical_range.start % BLOCK_SIZE != 0 || logical_range.end % BLOCK_SIZE != 0 {
67 return Err(anyhow!(
68 "logical_range boundaries must be a multiple of BLOCK_SIZE (4096 bytes), got {:?}",
69 logical_range
70 ));
71 }
72 if logical_range.start > logical_range.end {
73 return Err(anyhow!(
74 "logical_range.start must be <= logical_range.end, got {:?}",
75 logical_range
76 ));
77 }
78
79 let length_blocks = (logical_range.end - logical_range.start) / BLOCK_SIZE;
80 if let Some(dev_offset) = device_offset {
81 if dev_offset % BLOCK_SIZE != 0 {
82 return Err(anyhow!(
83 "device_offset must be a multiple of BLOCK_SIZE (4096 bytes), got {}",
84 dev_offset
85 ));
86 }
87
88 if length_blocks > MAX_REGULAR_EXTENT_BLOCKS {
89 return Err(anyhow!("Extent length bounds exceed maximum encodeable length"));
91 }
92
93 let target_block = dev_offset / BLOCK_SIZE;
94 if u32::try_from(target_block).is_err() {
95 return Err(anyhow!("Extent device_offset block index exceeds u32::MAX"));
96 }
97 } else {
98 if length_blocks > MAX_SPARSE_EXTENT_BLOCKS {
99 return Err(anyhow!("Extent length bounds exceed maximum encodeable length"));
101 }
102 }
103 Ok(Self { logical_range, device_offset })
104 }
105}
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq)]
111struct ExtentEntry {
112 end_logical_offset: u64,
113 device_offset: u64, }
115
116impl ExtentEntry {
117 const SPARSE_DEVICE_OFFSET: u64 = u64::MAX;
118
119 fn is_sparse(&self) -> bool {
120 self.device_offset == Self::SPARSE_DEVICE_OFFSET
121 }
122}
123
124fn encode_regular(length_blocks: u32, target_block: u32) -> u64 {
125 REGULAR | ((length_blocks as u64 & MAX_REGULAR_EXTENT_BLOCKS) << 32) | (target_block as u64)
126}
127
128fn encode_sparse(length_blocks: u64) -> u64 {
129 SPARSE | (length_blocks & !TYPE_MASK)
130}
131
132#[derive(Debug, Clone)]
134pub struct ExtentsIterator<'a> {
135 extents: &'a Extents,
136 index: usize,
137}
138
139impl<'a> Iterator for ExtentsIterator<'a> {
140 type Item = Extent;
141
142 fn next(&mut self) -> Option<Self::Item> {
143 if self.index < self.extents.entries.len() {
144 let res = self.extents.entry_to_result(self.index);
145 self.index += 1;
146 Some(res)
147 } else {
148 None
149 }
150 }
151}
152
153#[derive(Debug, Clone, PartialEq, Eq, Default)]
157pub struct Extents {
158 entries: Box<[ExtentEntry]>,
159}
160
161impl Extents {
162 pub fn encode_extents(extents: &[Extent]) -> Vec<u64> {
164 Self::encode_extents_iter(extents).collect()
165 }
166
167 pub fn encode_extents_iter<'a>(extents: &'a [Extent]) -> impl Iterator<Item = u64> + 'a {
169 extents.iter().map(|extent| {
170 let length_blocks = extent.len() / BLOCK_SIZE;
171 match extent.device_offset() {
172 Some(dev_offset) => {
173 let target_block = dev_offset / BLOCK_SIZE;
174 encode_regular(length_blocks as u32, target_block as u32)
175 }
176 None => encode_sparse(length_blocks),
177 }
178 })
179 }
180
181 pub fn from_encoded(encoded: &[u64]) -> Option<Self> {
184 let mut entries = Vec::with_capacity(encoded.len());
185 let mut current_logical_offset = 0;
186
187 for &val in encoded {
188 let kind = val & TYPE_MASK;
189 if kind == REGULAR {
190 let length_blocks = ((val & !TYPE_MASK) >> 32) as u64;
191 let target_block = (val & 0xffff_ffff) as u64;
192 let length_bytes = length_blocks * BLOCK_SIZE;
193 current_logical_offset += length_bytes;
194 entries.push(ExtentEntry {
195 end_logical_offset: current_logical_offset,
196 device_offset: target_block * BLOCK_SIZE,
197 });
198 } else if kind == SPARSE {
199 let length_blocks = (val & !TYPE_MASK) as u64;
200 let length_bytes = length_blocks * BLOCK_SIZE;
201 current_logical_offset += length_bytes;
202 entries.push(ExtentEntry {
203 end_logical_offset: current_logical_offset,
204 device_offset: ExtentEntry::SPARSE_DEVICE_OFFSET,
205 });
206 } else {
207 return None;
208 }
209 }
210
211 Some(Self { entries: entries.into_boxed_slice() })
212 }
213
214 pub fn iter_extents(&self, start_offset: u64) -> ExtentsIterator<'_> {
217 let index = self.entries.partition_point(|e| e.end_logical_offset <= start_offset);
218 ExtentsIterator { extents: self, index }
219 }
220
221 pub fn map(&self, offset: u64) -> Option<Extent> {
228 assert!(
229 offset % BLOCK_SIZE == 0,
230 "offset must be a multiple of BLOCK_SIZE (4096 bytes), got {offset}"
231 );
232 let idx = self.entries.partition_point(|e| e.end_logical_offset <= offset);
233 if idx >= self.entries.len() {
234 return None;
235 }
236
237 let entry = &self.entries[idx];
238 let start_logical = self.entry_start_offset(idx);
239 let end_logical = entry.end_logical_offset;
240
241 let offset_within = offset - start_logical;
242 let device_offset =
243 if entry.is_sparse() { None } else { Some(entry.device_offset + offset_within) };
244
245 Some(Extent { logical_range: offset..end_logical, device_offset })
246 }
247
248 pub fn mappings(&self) -> Vec<Extent> {
250 (0..self.entries.len()).map(|i| self.entry_to_result(i)).collect()
251 }
252
253 fn entry_start_offset(&self, idx: usize) -> u64 {
254 if idx == 0 { 0 } else { self.entries[idx - 1].end_logical_offset }
255 }
256
257 fn entry_to_result(&self, idx: usize) -> Extent {
258 let entry = &self.entries[idx];
259 let start_logical = self.entry_start_offset(idx);
260 let end_logical = entry.end_logical_offset;
261 let device_offset = if entry.is_sparse() { None } else { Some(entry.device_offset) };
262 Extent { logical_range: start_logical..end_logical, device_offset }
263 }
264}
265
266#[cfg(test)]
267mod tests {
268 use super::*;
269
270 #[test]
271 fn test_encode_decode_regular() {
272 let extents = vec![
273 Extent::new(0..(4 * BLOCK_SIZE), Some(10 * BLOCK_SIZE)),
274 Extent::new((4 * BLOCK_SIZE)..(6 * BLOCK_SIZE), Some(100 * BLOCK_SIZE)),
275 ];
276 let encoded = Extents::encode_extents(&extents);
277 assert_eq!(encoded.len(), 2);
278
279 let extents_container = Extents::from_encoded(&encoded).expect("from_encoded failed");
280
281 let decoded = extents_container.mappings();
282 assert_eq!(decoded.len(), 2);
283
284 assert_eq!(decoded[0].logical_range, 0..(4 * BLOCK_SIZE));
285 assert_eq!(decoded[0].device_offset, Some(10 * BLOCK_SIZE));
286
287 assert_eq!(decoded[1].logical_range, (4 * BLOCK_SIZE)..(6 * BLOCK_SIZE));
288 assert_eq!(decoded[1].device_offset, Some(100 * BLOCK_SIZE));
289 }
290
291 #[test]
292 fn test_encode_decode_sparse() {
293 let extents = vec![
294 Extent::new(0..(2 * BLOCK_SIZE), Some(50 * BLOCK_SIZE)),
295 Extent::new((2 * BLOCK_SIZE)..(5 * BLOCK_SIZE), None),
296 Extent::new((5 * BLOCK_SIZE)..(6 * BLOCK_SIZE), Some(200 * BLOCK_SIZE)),
297 ];
298 let encoded = Extents::encode_extents(&extents);
299
300 let extents_container = Extents::from_encoded(&encoded).expect("from_encoded failed");
301
302 let decoded = extents_container.mappings();
303 assert_eq!(decoded.len(), 3);
304
305 assert_eq!(decoded[0].logical_range, 0..(2 * BLOCK_SIZE));
306 assert_eq!(decoded[0].device_offset, Some(50 * BLOCK_SIZE));
307
308 assert_eq!(decoded[1].logical_range, (2 * BLOCK_SIZE)..(5 * BLOCK_SIZE));
309 assert_eq!(decoded[1].device_offset, None);
310
311 assert_eq!(decoded[2].logical_range, (5 * BLOCK_SIZE)..(6 * BLOCK_SIZE));
312 assert_eq!(decoded[2].device_offset, Some(200 * BLOCK_SIZE));
313 }
314
315 #[test]
316 fn test_binary_search_map_logical_offset() {
317 let extents = vec![
318 Extent::new(0..(10 * BLOCK_SIZE), Some(100 * BLOCK_SIZE)),
319 Extent::new((10 * BLOCK_SIZE)..(20 * BLOCK_SIZE), Some(200 * BLOCK_SIZE)),
320 Extent::new((20 * BLOCK_SIZE)..(30 * BLOCK_SIZE), Some(300 * BLOCK_SIZE)),
321 ];
322 let encoded = Extents::encode_extents(&extents);
323 let extents_container = Extents::from_encoded(&encoded).expect("from_encoded failed");
324
325 let mapped = extents_container.map(0).expect("should map at offset 0");
326 assert_eq!(mapped.logical_range, 0..(10 * BLOCK_SIZE));
327 assert_eq!(mapped.device_offset, Some(100 * BLOCK_SIZE));
328
329 let mapped_mid = extents_container
330 .map(12 * BLOCK_SIZE)
331 .expect("should map inside second extent via binary search");
332 assert_eq!(mapped_mid.logical_range, (12 * BLOCK_SIZE)..(20 * BLOCK_SIZE));
333 assert_eq!(mapped_mid.device_offset, Some(202 * BLOCK_SIZE));
334 }
335
336 #[test]
337 fn test_map_out_of_bounds() {
338 let extents = vec![Extent::new(0..(2 * BLOCK_SIZE), Some(10 * BLOCK_SIZE))];
339 let encoded = Extents::encode_extents(&extents);
340 let extents_container = Extents::from_encoded(&encoded).expect("from_encoded failed");
341
342 assert!(extents_container.map(2 * BLOCK_SIZE).is_none());
343 assert!(extents_container.map(100 * BLOCK_SIZE).is_none());
344 }
345
346 #[test]
347 fn test_binary_search_iter_extents() {
348 let extents = vec![
349 Extent::new(0..(2 * BLOCK_SIZE), Some(10 * BLOCK_SIZE)),
350 Extent::new((2 * BLOCK_SIZE)..(4 * BLOCK_SIZE), Some(20 * BLOCK_SIZE)),
351 Extent::new((4 * BLOCK_SIZE)..(6 * BLOCK_SIZE), Some(30 * BLOCK_SIZE)),
352 ];
353 let encoded = Extents::encode_extents(&extents);
354 let extents_container = Extents::from_encoded(&encoded).expect("from_encoded failed");
355
356 let results: Vec<_> = extents_container.iter_extents(3 * BLOCK_SIZE).collect();
357 assert_eq!(results.len(), 2);
358 assert_eq!(results[0].logical_range, (2 * BLOCK_SIZE)..(4 * BLOCK_SIZE));
359 assert_eq!(results[1].logical_range, (4 * BLOCK_SIZE)..(6 * BLOCK_SIZE));
360 }
361
362 #[test]
363 fn test_exact_boundary_queries() {
364 let extents = vec![
365 Extent::new(0..(10 * BLOCK_SIZE), Some(100 * BLOCK_SIZE)),
366 Extent::new((10 * BLOCK_SIZE)..(20 * BLOCK_SIZE), Some(200 * BLOCK_SIZE)),
367 ];
368 let encoded = Extents::encode_extents(&extents);
369 let extents_container = Extents::from_encoded(&encoded).expect("from_encoded failed");
370
371 let mapped = extents_container.map(10 * BLOCK_SIZE).expect("should map at exact boundary");
372 assert_eq!(mapped.logical_range, (10 * BLOCK_SIZE)..(20 * BLOCK_SIZE));
373 assert_eq!(mapped.device_offset, Some(200 * BLOCK_SIZE));
374
375 let results: Vec<_> = extents_container.iter_extents(10 * BLOCK_SIZE).collect();
376 assert_eq!(results.len(), 1);
377 assert_eq!(results[0].logical_range, (10 * BLOCK_SIZE)..(20 * BLOCK_SIZE));
378 }
379
380 #[test]
381 #[should_panic(expected = "multiple of BLOCK_SIZE")]
382 fn test_extent_new_unaligned_logical_start_panics() {
383 Extent::new(1..(2 * BLOCK_SIZE), Some(10 * BLOCK_SIZE));
384 }
385
386 #[test]
387 #[should_panic(expected = "multiple of BLOCK_SIZE")]
388 fn test_extent_new_unaligned_logical_end_panics() {
389 Extent::new(0..(2 * BLOCK_SIZE + 1), Some(10 * BLOCK_SIZE));
390 }
391
392 #[test]
393 #[should_panic(expected = "multiple of BLOCK_SIZE")]
394 fn test_extent_new_unaligned_device_offset_panics() {
395 Extent::new(0..(2 * BLOCK_SIZE), Some(10 * BLOCK_SIZE + 500));
396 }
397
398 #[test]
399 #[should_panic(expected = "multiple of BLOCK_SIZE")]
400 fn test_map_unaligned_offset_panics() {
401 Extents::default().map(500);
402 }
403
404 #[test]
405 fn test_iter_extents_unaligned_start_offset() {
406 let extents = vec![
407 Extent::new(0..(10 * BLOCK_SIZE), Some(100 * BLOCK_SIZE)),
408 Extent::new((10 * BLOCK_SIZE)..(20 * BLOCK_SIZE), Some(200 * BLOCK_SIZE)),
409 ];
410 let encoded = Extents::encode_extents(&extents);
411 let extents_container = Extents::from_encoded(&encoded).expect("from_encoded failed");
412 let results: Vec<_> = extents_container.iter_extents(500).collect();
413 assert_eq!(results.len(), 2);
414 assert_eq!(results[0].logical_range, 0..(10 * BLOCK_SIZE));
415 }
416
417 #[test]
418 fn test_encode_extents_device_offset_overflow_errors() {
419 let result = Extent::try_new(0..BLOCK_SIZE, Some((u32::MAX as u64 + 1) * BLOCK_SIZE));
420 assert!(result.is_err());
421 assert_eq!(
422 result.unwrap_err().to_string(),
423 "Extent device_offset block index exceeds u32::MAX"
424 );
425 }
426
427 #[test]
428 fn test_encode_extents_regular_length_overflow_errors() {
429 let result = Extent::try_new(
430 0..((MAX_REGULAR_EXTENT_BLOCKS + 1) * BLOCK_SIZE),
431 Some(10 * BLOCK_SIZE),
432 );
433 assert!(result.is_err());
434 assert_eq!(
435 result.unwrap_err().to_string(),
436 "Extent length bounds exceed maximum encodeable length"
437 );
438 }
439
440 #[test]
441 fn test_from_encoded_unknown_kind_returns_none() {
442 let unknown_descriptor = 0x40000000_00000000;
443 assert!(Extents::from_encoded(&[unknown_descriptor]).is_none());
444 }
445}