Build a file with a deterministic sparse layout: write each `(off, len, byte)` data extent, then punch every gap into a real hole. The resulting `SEEK_DATA`/`SEEK_HOLE` extents match `data` exactly, regardless of folio/THP allocation policy on the backing FS.
(f: &std::fs::File, total: u64, data: &[(u64, u64, u8)])
| 3372 | /// The resulting `SEEK_DATA`/`SEEK_HOLE` extents match `data` exactly, |
| 3373 | /// regardless of folio/THP allocation policy on the backing FS. |
| 3374 | fn sparse_layout(f: &std::fs::File, total: u64, data: &[(u64, u64, u8)]) { |
| 3375 | f.set_len(total).unwrap(); |
| 3376 | for &(off, len, byte) in data { |
| 3377 | f.write_all_at(&vec![byte; len as usize], off).unwrap(); |
| 3378 | } |
| 3379 | let mut sorted: Vec<(u64, u64)> = data.iter().map(|&(o, l, _)| (o, l)).collect(); |
| 3380 | sorted.sort_unstable(); |
| 3381 | let mut cursor = 0u64; |
| 3382 | for (off, len) in sorted { |
| 3383 | assert!(off >= cursor, "overlapping data extents"); |
| 3384 | if off > cursor { |
| 3385 | punch_hole(f, cursor, off - cursor); |
| 3386 | } |
| 3387 | cursor = off + len; |
| 3388 | } |
| 3389 | if cursor < total { |
| 3390 | punch_hole(f, cursor, total - cursor); |
| 3391 | } |
| 3392 | } |
| 3393 | |
| 3394 | #[test] |
| 3395 | fn empty_memfd_has_no_data_extents() { |