MCPcopy Create free account
hub / github.com/cloud-hypervisor/cloud-hypervisor / compress_allocated_clusters

Function compress_allocated_clusters

block/src/qcow_common.rs:335–409  ·  view source on GitHub ↗

Compress every allocated cluster in a QCOW2 image file in place. Walks L1 -> L2 tables, compresses each standard cluster with raw deflate, appends the compressed payload at the end of the file, and rewrites the L2 entry with the compressed layout.

(file: &mut File)

Source from the content-addressed store, hash-verified

333 /// deflate, appends the compressed payload at the end of the file,
334 /// and rewrites the L2 entry with the compressed layout.
335 pub fn compress_allocated_clusters(file: &mut File) {
336 file.seek(SeekFrom::Start(HEADER_CLUSTER_BITS_OFFSET))
337 .unwrap();
338 let cluster_bits = file.read_u32::<BigEndian>().unwrap();
339 let cluster_size = 1u64 << cluster_bits;
340
341 file.seek(SeekFrom::Start(HEADER_L1_SIZE_OFFSET)).unwrap();
342 let l1_size = file.read_u32::<BigEndian>().unwrap();
343
344 file.seek(SeekFrom::Start(HEADER_L1_TABLE_OFFSET)).unwrap();
345 let l1_table_offset = file.read_u64::<BigEndian>().unwrap();
346
347 let entries_per_l2 = cluster_size / 8;
348
349 let mut append_offset = file.seek(SeekFrom::End(0)).unwrap();
350 append_offset = (append_offset + 511) & !511;
351
352 for l1_idx in 0..l1_size as u64 {
353 let l1_entry_offset = l1_table_offset + l1_idx * 8;
354 file.seek(SeekFrom::Start(l1_entry_offset)).unwrap();
355 let l1_entry = file.read_u64::<BigEndian>().unwrap();
356
357 let l2_table_addr = l1_entry & L1_L2_ADDR_MASK;
358 if l2_table_addr == 0 {
359 continue;
360 }
361
362 for l2_idx in 0..entries_per_l2 {
363 let l2_entry_offset = l2_table_addr + l2_idx * 8;
364 file.seek(SeekFrom::Start(l2_entry_offset)).unwrap();
365 let l2_entry = file.read_u64::<BigEndian>().unwrap();
366
367 if l2_entry & CLUSTER_USED_FLAG == 0 || l2_entry & COMPRESSED_FLAG != 0 {
368 continue;
369 }
370
371 let host_cluster_addr = l2_entry & L1_L2_ADDR_MASK;
372 if host_cluster_addr == 0 {
373 continue;
374 }
375
376 let mut cluster_data = vec![0u8; cluster_size as usize];
377 file.seek(SeekFrom::Start(host_cluster_addr)).unwrap();
378 file.read_exact(&mut cluster_data).unwrap();
379
380 let mut encoder = DeflateEncoder::new(Vec::new(), Compression::default());
381 encoder.write_all(&cluster_data).unwrap();
382 let compressed = encoder.finish().unwrap();
383
384 file.seek(SeekFrom::Start(append_offset)).unwrap();
385 file.write_all(&compressed).unwrap();
386
387 // The L2 entry encodes the compressed size in units of
388 // 512 byte sectors. The reader decodes the sector count
389 // back and computes: nsectors * 512 - (addr & 511).
390 // Because addr is 512 aligned, this yields nsectors * 512
391 // which rounds up to the next sector boundary. The file
392 // must contain enough bytes for that rounded up pread.

Callers 3

test_compressed_readFunction · 0.85
test_compressed_readFunction · 0.85

Calls 6

newFunction · 0.85
make_compressed_l2_entryFunction · 0.85
finishMethod · 0.80
seekMethod · 0.45
lenMethod · 0.45
flushMethod · 0.45

Tested by 3

test_compressed_readFunction · 0.68
test_compressed_readFunction · 0.68