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