Re: [PATCH] erofs-utils: mkfs: also handle last compacted 2B pack in z_erofs_drop_inline_pcluster

Gao Xiang <[email protected]>
Newsgroups org.ozlabs.lists.linux-erofs
Message-ID <[email protected]>

On 2026/5/18 15:28, Zhiguo Niu wrote:
> Gao Xiang <[email protected]> 于2026年5月18日周一 12:18写道:
>>
>> Hi Zhiguo,
>>
>> On 2026/5/11 15:54, Zhiguo Niu wrote:
>>> Gao Xiang <[email protected]> 于2026年5月11日周一 12:01写道:
>>>>
>>>> Hi Zhiguo,
>>>>
>>>> On 2026/4/29 15:59, Zhiguo Niu wrote:
>>>>> With ztailpacking enabled, the current process assumes that a compacted_4b_end
>>>>> always exists in the compacted pack. However, in some specific files, the
>>>>> compacted pack may not have a compacted_4b_end. This leads to an incorrect
>>>>> modification of the last compacted_2B entry, resulting in incorrect modification
>>>>> of its clusterofs. In subsequent fsck operations, incorrect parameters will
>>>>> affect the decompression of the penultimate pcluster.
>>>>>
>>>>> This patch determines whether the last entry of the current compacted pack
>>>>> belongs to compacted 2B or 4B and then updates the correct bits accordingly.
>>>>>
>>>>> Fixes: a7c1f0575ef8 ("erofs-utils: lib: refine tailpcluster compression approach")
>>>>> Signed-off-by: Zhiguo Niu <[email protected]>
>>>>
>>>> Sorry for late response.
>>>>
>>>> I do think the issue is valid, but either the previous
>>>> solution or the proposed one is ugly.
>>>
>>> Hi Xiang,
>>> Yes it would be ideal if the same piece of common code could cover
>>> both scenarios.
>>> But I haven't figured it out yet, so I'll distinguish them like this for now. ^^
>>> thanks!
>>>>
>> Could you confirm if the following diff fixes the issue?
> Hi Xiang,
> Just confirming a few minor issues:
>>
>>
>> diff --git a/include/erofs/defs.h b/include/erofs/defs.h
>> index 9f3d0f9c35bc..0e4c2a9b53c7 100644
>> --- a/include/erofs/defs.h
>> +++ b/include/erofs/defs.h
>> @@ -218,6 +218,11 @@ typedef int64_t         s64;
>>    #define get_unaligned(ptr)    __get_unaligned_t(typeof(*(ptr)), (ptr))
>>    #define put_unaligned(val, ptr) __put_unaligned_t(typeof(*(ptr)), (val), (ptr))
>>
>> +static inline u32 get_unaligned_le16(const void *p)
>> +{
>> +       return le32_to_cpu(__get_unaligned_t(__le16, p));
>> +}
>> +
>>    static inline u32 get_unaligned_le32(const void *p)
>>    {
>>          return le32_to_cpu(__get_unaligned_t(__le32, p));
>> diff --git a/include/erofs/internal.h b/include/erofs/internal.h
>> index 450e2647cca7..2cc9cc8009aa 100644
>> --- a/include/erofs/internal.h
>> +++ b/include/erofs/internal.h
>> @@ -210,6 +210,12 @@ struct erofs_diskbuf;
>>    #define EROFS_INODE_DATA_SOURCE_RESVSP                3
>>    #define EROFS_INODE_DATA_SOURCE_REBUILD_BLOB  4
>>
>> +enum erofs_idata_type {
>> +       EROFS_IDATA_TYPE_RAW,
>> +       EROFS_IDATA_TYPE_COMPRESSED_DEFAULT,
>> +       EROFS_IDATA_TYPE_COMPRESSED_END_OF_2B,
>> +};
>> +
>>    #define EROFS_I_BLKADDR_DEV_ID_BIT            48
>>
>>    struct erofs_inode {
>> @@ -262,7 +268,7 @@ struct erofs_inode {
>>          unsigned short idata_size;
>>          char datasource;
>>          bool in_metabox;
>> -       bool compressed_idata;
>> +       char idata_type;
>>          bool lazy_tailblock;
>>          bool opaque;
>>          /* OVL: non-merge dir that may contain whiteout entries */
>> diff --git a/lib/compress.c b/lib/compress.c
>> index 62d2672cb665..e171aee48c0b 100644
>> --- a/lib/compress.c
>> +++ b/lib/compress.c
>> @@ -483,7 +483,7 @@ static int z_erofs_fill_inline_data(struct erofs_inode *inode, void *data,
>>    {
>>          inode->z_advise |= Z_EROFS_ADVISE_INLINE_PCLUSTER;
>>          inode->idata_size = len;
>> -       inode->compressed_idata = !raw;
>> +       inode->idata_type = EROFS_IDATA_TYPE_COMPRESSED_DEFAULT;
>>
>>          inode->idata = malloc(inode->idata_size);
>>          if (!inode->idata)
>> @@ -980,7 +980,8 @@ int z_erofs_convert_to_compacted_format(struct erofs_inode *inode,
>>                                                &dummy_head, big_pcluster);
>>                  compacted_2b -= 16;
>>          }
>> -       DBG_BUGON(compacted_2b);
>> +       if (!compacted_4b_end && inode->idata_size)
>> +               inode->idata_type = EROFS_IDATA_TYPE_COMPRESSED_END_OF_2B;
> if  compacted_2b && compacted_4b_end both are zero,  should not set this???

Yes, maybe it should be ahead of
`while (compacted_2b)`, and

if (compacted_2b) {
	if (!compacted_4b_end && inode->idata_size)
		inode->idata_type = EROFS_IDATA_TYPE_COMPRESSED_END_OF_2B;
	do {
		...
	} while(compacted_2b);
}


>>
>>          /* generate compacted_4b_end */
>>          while (compacted_4b_end > 1) {
>> @@ -1210,10 +1211,12 @@ void z_erofs_drop_inline_pcluster(struct erofs_inode *inode)
>>
>>          h->h_advise = cpu_to_le16(le16_to_cpu(h->h_advise) &
>>                                    ~Z_EROFS_ADVISE_INLINE_PCLUSTER);
>> +       DBG_BUGON(inode->idata_size != le16_to_cpu(h->h_idata_size));
>>          h->h_idata_size = 0;
>> +
>>          if (!inode->eof_tailraw)
>>                  return;
>> -       DBG_BUGON(inode->compressed_idata != true);
>> +       DBG_BUGON(inode->idata_type != EROFS_IDATA_TYPE_RAW);
>   DBG_BUGON(inode->idata_type != EROFS_IDATA_TYPE_COMPRESSED_DEFAULT); ???

It should be

DBG_BUGON(inode->idata_type == EROFS_IDATA_TYPE_RAW);


>>
>>          /* patch the EOF lcluster to uncompressed type first */
>>          if (inode->datalayout == EROFS_INODE_COMPRESSED_FULL) {
>> @@ -1224,18 +1227,26 @@ void z_erofs_drop_inline_pcluster(struct erofs_inode *inode)
>>                  di->di_advise = cpu_to_le16(type);
>>          } else if (inode->datalayout == EROFS_INODE_COMPRESSED_COMPACT) {
>>                  /* handle the last compacted 4B pack */
>> -               unsigned int eofs, base, pos, v, lo;
>> +               unsigned int lclusterbits = inode->z_lclusterbits;
>> +               unsigned int lobits, eofs, base, pos, v;
>>                  u8 *out;
>>
>> -               eofs = inode->extent_isize -
>> -                       (4 << (BLK_ROUND_UP(sbi, inode->i_size) & 1));
>> -               base = round_down(eofs, 8);
>> -               pos = 16 /* encodebits */ * ((eofs - base) / 4);
>> -               out = inode->compressmeta + base;
>> -               lo = erofs_blkoff(sbi, get_unaligned_le32(out + pos / 8));
>> -               v = (type << sbi->blkszbits) | lo;
>> -               out[pos / 8] = v & 0xff;
>> -               out[pos / 8 + 1] = v >> 8;
>> +               lobits = max(lclusterbits, ilog2(Z_EROFS_LI_D0_CBLKCNT) + 1U);
>> +
>> +               if (inode->idata_type == EROFS_IDATA_TYPE_COMPRESSED_DEFAULT) {
>> +                       eofs = inode->extent_isize -
>> +                               (4 << (BLK_ROUND_UP(sbi, inode->i_size) & 1));
>> +                       base = round_down(eofs, 8);
>> +                       pos = 16 /* encodebits */ * ((eofs - base) / 4);
>> +                       out = inode->compressmeta + base + pos / 8;
>> +               } else {
>> +                       out = inode->compressmeta + inode->extent_isize - 4 - 2;
>> +                       lobits = 16 - 14 /* encodebits */ + lobits;
> if  compacted 2B, lobits=2+12=14, but encodebis =14, clusterofbits
> should be 12??
> Or is there something I'm misunderstanding?

Not sure what you say, basically compacted 2B
encodebits == 14 all the time,

and the last item should be the highest 14 bits,

so

|                    16 bits.             |
| <----  14 bits ---->|
|  2bits |  12 or 11  | 2 bits
| type   |    lobits  | the previous item |
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.