Re: [PATCH v1 1/6] tools/migration: introduce PAGE_DATA_LZ4 stream record type

Marcus Granado <[email protected]> Tue, 4 Aug 2026 13:25:59 +0000
Newsgroups gmane.comp.emulators.xen.devel
Message-ID <LV4PR03MB823492BF26528F6FAC11CC3AEDD42@LV4PR03MB8234.namprd03.prod.outlook.com>
On Tue, 4 Aug 2026 at 10:27, Frediano Ziglio <[email protected]> wrote:=0A=
> On Tue, 4 Aug 2026 at 10:15, Teddy Astie <[email protected]> wrote:=
=0A=
>>=0A=
>> Le 03/08/2026 =E0 19:23, Marcus Granado a =E9crit :=0A=
>>> simplify to reusing PAGE_DATA and spending one octet of its reserved wo=
rd=0A=
>>> as follows:=0A=
>>>=0A=
>>>=0A=
>>>       0     1     2     3     4     5     6     7 octet=0A=
>>>      +-----------------------+-----+-------------------+=0A=
>>>      | count (C)             | comp| (reserved)        |=0A=
>>>      +-----------------------+-----+-------------------+=0A=
>>>      | pfn[0]                                          |=0A=
>>>      +-------------------------------------------------+=0A=
>>>      ...=0A=
>>>      +-------------------------------------------------+=0A=
>>>      | pfn[C-1]                                        |=0A=
>>>      +-------------------------------------------------+=0A=
>>>      | page_data[0..N-1] if comp =3D=3D 0                  |=0A=
>>>      | or page_cdata     if comp !=3D 0                  |=0A=
>>>      +-------------------------------------------------+=0A=
>>>=0A=
>>> with two new entries in the field table:=0A=
>>>=0A=
>>> comp        Compression algorithm applied to the page contents. 0=0A=
>>>              means none, and the record is exactly as it is today. 1=0A=
>>>              means LZ4 block format. Other values are reserved for=0A=
>>>              other future formats like ZSTD etc. A comp !=3D 0 can only=
=0A=
>>>              be emitted if 0 < len(page_cdata) < N * page_size. An=0A=
>>>              unknown comp must cause the receiver to fail with a=0A=
>>>              "Compression algorithm <value> not handled" error.=0A=
>>>=0A=
>>> page_cdata  Present instead of page_data when comp is non-zero. A=0A=
>>>              single compressed object holding the concatenation of the=
=0A=
>>>              N page_data entries. The receiver must verify that=0A=
>>>              0 < count <=3D MAX_BATCH_SIZE.=0A=
>>>=0A=
>>>=0A=
>>> Teddy, I hope this format covers your points: it's no longer LZ4 specif=
ic,=0A=
>>> the inline clen inconsistency in libxenguest record disappears, it's on=
e=0A=
>>> block over an immutable copy of the batch instead of one per page, the=
=0A=
>>> decompressed size is known up front, and the allocation derived from co=
unt=0A=
>>> is bounded on the receiver.=0A=
>>>=0A=
>>=0A=
>> Looks good to me.=0A=
>>=0A=
>>> On Wed, 22 Jul 2026 at 20:42, Frediano Ziglio <[email protected]> wrot=
e:=0A=
>>>> Don't we need to bump the version number while we add a new mandatory=
=0A=
>>>> record?=0A=
>>>=0A=
>>> I believe we may avoid having to do a version bump if we adopt the prop=
erty=0A=
>>> that 0 < len(page_cdata) < N * page_size when comp !=3D 0, as in this c=
ase=0A=
>>> the compressed data sent to an old receiver would fail in handle_page_d=
ata()=0A=
>>> with "PAGE_DATA record wrong size". Bumping the version would make=0A=
>>> uncompressed migrations fail if they are sent to old receivers that als=
o=0A=
>>> understand uncompressed migration, so avoiding if possible would be goo=
d.=0A=
>>> The spec says migration tools "shall always save images using version V=
",=0A=
>>> so it doesn't seem like we could bump the version only when compression=
 is=0A=
>>> on.=0A=
=0A=
=0A=
Thanks. I will take the discussion so far as the record format above being=
=0A=
agreed, so the only open point is how it is carried.=0A=
=0A=
>> The specification says=0A=
>>=0A=
>>  > Padding and reserved fields are set to zero on save and must be=0A=
>> ignored during restore.=0A=
>>=0A=
>> Which is not really going to help if we add a new field that matters on=
=0A=
>> how the content is organized.=0A=
=0A=
Agreed that the sentence as it stands does not cover it, but I think that=
=0A=
is a documentation problem rather than a format problem: once the octet is=
=0A=
given a meaning by the specification it is no longer a reserved field, so=
=0A=
the rule stops applying to it. The v2 spec patch would define comp in the=
=0A=
PAGE_DATA field table alongside count and pfn, and leave the remaining=0A=
three octets reserved and required to be zero.=0A=
=0A=
To make the compatibility argument rest on the specification rather than on=
=0A=
one implementation, I would also add these rules to it in the same patch:=
=0A=
=0A=
* a saver may only emit comp !=3D 0 when 0 < len(page_cdata) < N * page_siz=
e=0A=
* a restoring side must reject a PAGE_DATA record whose length is not=0A=
  exactly sizeof(hdr) + C * 8 + N * page_size when comp =3D=3D 0=0A=
* a restoring side must reject a record with count > MAX_BATCH_SIZE, and=0A=
  must fail on a comp value it does not implement=0A=
=0A=
The second is what handle_page_data() already does today, so writing it=0A=
down in the specification is easy and turns the PAGE_DATA argument below=0A=
into a guarantee rather than an observation about the current code.=0A=
=0A=
> Yes, there's no check for "_res1" being 0, however there's this check:=0A=
>    if ( rec->length !=3D (sizeof(*pages) +  ...=0A=
> so, as long as we require that the compressed data is less than the=0A=
> uncompressed one (we should) it's fine.=0A=
=0A=
> Not strong but if I could vote I would just use part of "_res1" as=0A=
> proposed.=0A=
=0A=
I would vote the same way. To be explicit about it: an old receiver=0A=
will reject a compressed record through the length check rather than=0A=
through the mandatory record rule, so the diagnostic is "PAGE_DATA record=
=0A=
wrong size" rather than one naming the unsupported compression. I think=0A=
that is an acceptable price for not adding a record type, given the strict=
=0A=
inequality above makes the rejection guaranteed rather than incidental.=0A=
=0A=
Andrew, Roger, the one open point is whether to carry this in a PAGE_DATA=
=0A=
reserved octet or in a separate PAGE_DATA_COMPRESSED mandatory record.=0A=
Unless a maintainer prefers the latter, I will implement v2 with the comp=
=0A=
octet in PAGE_DATA and the three rules above.=0A=
=0A=
Marcus=0A=
=0A=