From 8386637fcd83a069527aebecdca5bb67988fe087 Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Sun, 15 Mar 2026 17:19:10 +0000 Subject: [PATCH] images: Add compressed page metadata Present pagemap entries currently imply one PAGE_SIZE payload per page. That is not enough to locate packed zero, raw, and LZ4 blocks or to describe region compression. Record the compression mode and region size in the inventory. Add packed per-block sizes, their total, and the region width to pagemap entries, plus PE_PAYLOAD_ALIGNED for entries whose payload starts after padding. Keep the fields optional so ordinary and older images retain their existing representation. Assisted-by: Codex:GPT-5 Signed-off-by: Radostin Stoyanov --- images/inventory.proto | 10 ++++++++++ images/pagemap.proto | 35 +++++++++++++++++++++++++++++++++++ lib/pycriu/images/pb2dict.py | 1 + 3 files changed, 46 insertions(+) diff --git a/images/inventory.proto b/images/inventory.proto index feed5b850..fc1fd081f 100644 --- a/images/inventory.proto +++ b/images/inventory.proto @@ -34,4 +34,14 @@ message inventory_entry { // network locking rule. optional string dump_criu_run_id = 13; optional bool allow_uprobes = 14; + /* + * Memory page compression mode. Encodes enum compress_mode: + * 0 = COMPRESS_OFF + * 1 = COMPRESS_PER_PAGE + * 2 = COMPRESS_REGION + * Absent or 0 means no compression was applied to the dump. + */ + optional uint32 compress = 15; + /* Region size in bytes when compress = 2. Informational. */ + optional uint32 compress_region_size = 16; } diff --git a/images/pagemap.proto b/images/pagemap.proto index f2436a51a..08148c9bb 100644 --- a/images/pagemap.proto +++ b/images/pagemap.proto @@ -12,6 +12,41 @@ message pagemap_entry { required uint64 vaddr = 1 [(criu).hex = true]; required uint32 compat_nr_pages = 2; optional bool in_parent = 3; + /* + * PE_PAYLOAD_ALIGNED means that payload bytes for this present entry + * begin at the next host-page boundary in pages-*.img. Readers must skip + * the padding before applying compressed_size[] or the ordinary raw size. + */ optional uint32 flags = 4 [(criu).flags = "pmap.flags" ]; optional uint64 nr_pages = 5; + /* + * Size in bytes of each compressed block stored in the pages image. + * One element per block: per page in per-page mode, per region in + * region mode (see region_pages). Two values are special: + * 0 = all-zero block, no payload is stored in the image. + * N = stored raw (incompressible), where N is the block's + * uncompressed byte size: PAGE_SIZE in per-page mode, or + * block_pages * PAGE_SIZE in region mode (the last region + * of an entry may hold fewer than region_pages pages). + * Any other value is the length of the LZ4-compressed payload. + * + * Packed encoding avoids one protobuf tag per memory page. + */ + repeated uint32 compressed_size = 6 [packed = true]; + /* + * Sum of all compressed_size[] entries: the total number of payload + * bytes this entry occupies in the pages image. On restore it is an + * O(1) shortcut to advance the read offset past a whole entry (see + * skip_pagemap_pages()) instead of summing compressed_size[] block by + * block. Offsets into the interior of an entry are still derived by + * walking compressed_size[], since a single total cannot locate an + * individual page. + */ + optional uint64 total_compressed_size = 7; + /* + * If set and > 0, compressed_size[] holds one element per region of + * region_pages pages (the last region may be shorter than nr_pages % + * region_pages). If unset or 0, compressed_size[] is per-page. + */ + optional uint32 region_pages = 8; } diff --git a/lib/pycriu/images/pb2dict.py b/lib/pycriu/images/pb2dict.py index 6c687aace..9d6b748ff 100644 --- a/lib/pycriu/images/pb2dict.py +++ b/lib/pycriu/images/pb2dict.py @@ -148,6 +148,7 @@ pmap_flags_map = [ ('PE_PARENT', 1 << 0), ('PE_LAZY', 1 << 1), ('PE_PRESENT', 1 << 2), + ('PE_PAYLOAD_ALIGNED', 1 << 3), ] flags_maps = {