Re: erofs pointer corruption and kernel crash

From: Arseniy Krasnov

Date: Fri Apr 10 2026 - 07:37:59 EST




10.04.2026 11:31, Gao Xiang wrote:
> Hi,
>
> On 2026/4/10 16:13, Arseniy Krasnov wrote:
>> Hi,
>>
>> We found unexpected behaviour of erofs:
>>
>> There is function in erofs - 'erofs_onlinefolio_end()'. It has pointer to
>> 'struct folio' as first argument, and there is loop inside this function,
>> which updates 'private' field of provided folio:
>>
>>    do {
>>            orig = atomic_read((atomic_t *)&folio->private);
>>            DBG_BUGON(orig <= 0);
>>            v = dirty << EROFS_ONLINEFOLIO_DIRTY;
>>            v |= (orig - 1) | (!!err << EROFS_ONLINEFOLIO_EIO);
>>    } while (atomic_cmpxchg((atomic_t *)&folio->private, orig, v) != orig);
>>
>> Now, we see that in some rare case, this function processes folio, where
>> 'private' is pointer, and thus this loop will update some bits in this
>> pointer. Then later kernel dereferences such pointer and crashes.
>>
>> To catch this, the following small debug patch was used (e.g. we check that 'private' field is pointer):
>>
>> diff --git a/fs/erofs/data.c b/fs/erofs/data.c
>> index 33cb0a7330d2..b1d8deffec4d 100644
>> --- a/fs/erofs/data.c
>> +++ b/fs/erofs/data.c
>> @@ -238,6 +238,11 @@ void erofs_onlinefolio_end(struct folio *folio, int err, bool dirty)
>>   {
>>       int orig, v;
>>   +    if (((uintptr_t)folio->private) & 0xffff000000000000) {
>
> No, if erofs_onlinefolio_end() is called, `folio->private`
> shouldn't be a pointer, it's just a counter inside, and
> storing a pointer is unexpected.
>
> And since the folio is locked, it shouldn't call into
> try_to_free_buffers().
>
> Is it easy to reproduce? if yes, can you print other
> values like `folio->mapping` and `folio->index` as
> well?
>
> I need more informations to find some clues.



So reproduced again with this debug patch which adds magic to 'struct z_erofs_pcluster' and prints 'struct folio'
when pointer in 'private' is passed to 'erofs_onlinefolio_end()'. In short - 'private' points to 'struct z_erofs_pcluster'.

Patch itself:


diff --git a/fs/erofs/data.c b/fs/erofs/data.c
index 33cb0a7330d2..6eb975facce1 100644
--- a/fs/erofs/data.c
+++ b/fs/erofs/data.c
@@ -234,10 +234,132 @@ void erofs_onlinefolio_split(struct folio *folio)
atomic_inc((atomic_t *)&folio->private);
}

+static void dump_folio_address_space(const struct address_space *mapping)
+{
+ pr_emerg("[foliodbg] %s struct address_space (%p):\ni_ino=0x%lx\ns_dev=0x%x\n"
+ "i_rdev=0x%x\ngfp_mask=%lx\ni_mmap_writable=%d\nnrpages=%lu\n"
+ "writeback_index=%lu flags=0x%lx\nwb_err=%x\ni_private_data=%px\n"
+ "\n",
+ __func__, mapping,
+ (mapping && mapping->host) ? mapping->host->i_ino : 0,
+ (mapping && mapping->host && mapping->host->i_sb) ? mapping->host->i_sb->s_dev : 0,
+ (mapping && mapping->host) ? mapping->host->i_rdev : 0,
+ mapping ? (unsigned long)mapping->gfp_mask : 0,
+ mapping ? atomic_read(&mapping->i_mmap_writable) : 0,
+ mapping ? mapping->nrpages : 0,
+ mapping ? mapping->writeback_index : 0,
+ mapping ? mapping->flags : 0,
+ mapping ? mapping->wb_err : 0,
+ mapping ? mapping->i_private_data : NULL
+ );
+}
+
+static void dump_folio_page(const struct page *page)
+{
+ pr_emerg("[foliodbg] %s struct page (%p):\nflags=0x%lx\nindex=%lu\n"
+ "privat=0x%lx\npage_type(mapcount)=0x%x\n"
+#ifdef CONFIG_MEMCG
+ "memcg_data=0x%lx\n"
+#elif defined(CONFIG_SLAB_OBJ_EXT)
+ "unused_slab_obj_exts=0x%lx\n"
+#endif
+#if defined(WANT_PAGE_VIRTUAL)
+ "virtual=%p\n"
+#endif
+#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
+ "_last_cpupid=%d\n"
+#endif
+ "refcount=%d\n"
+ "\n",
+ __func__, page, page->flags, page->index, page->private,
+ page->page_type,
+#ifdef CONFIG_MEMCG
+ page->memcg_data,
+#elif defined(CONFIG_SLAB_OBJ_EXT)
+ page->_unused_slab_obj_exts,
+#endif
+#if defined(WANT_PAGE_VIRTUAL)
+ page->virtual,
+#endif
+#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
+ page->_last_cpupid,
+#endif
+ atomic_read(&page->_refcount)
+ );
+}
+
+static void dump_folio(const struct folio *folio)
+{
+ pr_emerg("[foliodbg] %s struct folio (%p):\nflags=0x%lx\nindex=%lu\n"
+ "private=%px\nmapcount=%d\nrefcount=%d\n"
+#ifdef CONFIG_MEMCG
+ "memcg_data=0x%lx\n"
+#elif defined(CONFIG_SLAB_OBJ_EXT)
+ "unused_slab_obj_exts=0x%lx\n"
+#endif
+#if defined(WANT_PAGE_VIRTUAL)
+ "virtual=%p\n"
+#endif
+#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
+ "_last_cpupid=%d\m"
+#endif
+ "flags_1=0x%lx\nhead_1=0x%lx\nlarge_mapcount=%d\nnr_pages_mapped=%d\n"
+#ifdef CONFIG_64BIT
+ "entire_mapcount=%d\npincount=%d\n"
+#endif /* CONFIG_64BIT */
+ "mm_id_mapcount=[%d, %d]\nmapcount_1=%d\nrefcount_1=%d\n"
+#ifdef NR_PAGES_IN_LARGE_FOLIO
+ "nr_pages=%d\n"
+#endif /* NR_PAGES_IN_LARGE_FOLIO */
+ "flags_2=0x%lx\nhead_2=0x%lx\n"
+ "flags_3=0x%lx\nhead_3=0x%lx\n"
+ "\n",
+ __func__, folio,
+ folio->flags, folio->index, folio->private,
+ atomic_read(&folio->_mapcount), atomic_read(&folio->_refcount),
+#ifdef CONFIG_MEMCG
+ folio->memcg_data,
+#elif defined(CONFIG_SLAB_OBJ_EXT)
+ folio->_unused_slab_obj_exts,
+#endif
+#if defined(WANT_PAGE_VIRTUAL)
+ folio->virtual,
+#endif
+#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
+ folio->_last_cpupid,
+#endif
+ folio->_flags_1, folio->_head_1,
+ atomic_read(&folio->_large_mapcount),
+ atomic_read(&folio->_nr_pages_mapped),
+#ifdef CONFIG_64BIT
+ atomic_read(&folio->_entire_mapcount),
+ atomic_read(&folio->_pincount),
+#endif /* CONFIG_64BIT */
+ folio->_mm_id_mapcount[0], folio->_mm_id_mapcount[1],
+ atomic_read(&folio->_mapcount_1),
+ atomic_read(&folio->_refcount_1),
+#ifdef NR_PAGES_IN_LARGE_FOLIO
+ folio->_nr_pages,
+#endif /* NR_PAGES_IN_LARGE_FOLIO */
+ folio->_flags_2, folio->_head_2,
+ folio->_flags_3, folio->_head_3
+ );
+
+ dump_folio_page(&folio->page);
+ dump_folio_address_space(folio->mapping);
+ print_hex_dump(KERN_EMERG, "folio private", DUMP_PREFIX_ADDRESS, 16, 1,
+ folio->private, 32, true);
+}
void erofs_onlinefolio_end(struct folio *folio, int err, bool dirty)
{
int orig, v;

+ if (((uintptr_t)folio->private) & 0xffff000000000000) {
+ pr_emerg("\n[foliodbg] %s:%d EROFS FOLIO %px PRIVATE BEFORE %px\n", __func__, __LINE__, folio, folio->private);
+ dump_folio(folio);
+ dump_stack();
+ }
+
do {
orig = atomic_read((atomic_t *)&folio->private);
DBG_BUGON(orig <= 0);
@@ -245,6 +367,9 @@ void erofs_onlinefolio_end(struct folio *folio, int err, bool dirty)
v |= (orig - 1) | (!!err << EROFS_ONLINEFOLIO_EIO);
} while (atomic_cmpxchg((atomic_t *)&folio->private, orig, v) != orig);

+ if (((uintptr_t)folio->private) & 0xffff000000000000)
+ pr_emerg("\n[foliodbg] %s:%d EROFS FOLIO %px PRIVATE SET %px\n", __func__, __LINE__, folio, folio->private);
+
if (v & (BIT(EROFS_ONLINEFOLIO_DIRTY) - 1))
return;
folio->private = 0;
diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c
index d21ae4802c7f..e8f295e90b05 100644
--- a/fs/erofs/zdata.c
+++ b/fs/erofs/zdata.c
@@ -38,6 +38,7 @@ __Z_EROFS_BVSET(z_erofs_bvset_inline, Z_EROFS_INLINE_BVECS);
* A: Field should be accessed / updated in atomic for parallelized code.
*/
struct z_erofs_pcluster {
+ u64 magic;
struct mutex lock;
struct lockref lockref;

@@ -262,6 +263,8 @@ static struct z_erofs_pcluster *z_erofs_alloc_pcluster(unsigned int size)
pcl = kmem_cache_zalloc(pcs->slab, GFP_KERNEL);
if (!pcl)
return ERR_PTR(-ENOMEM);
+
+ pcl->magic = 0x435053464F52455AULL;
return pcl;
}
return ERR_PTR(-EINVAL);



Crash result (tail of log was corrupted a little due to second sequential catch of this problem):



[ 684.634126][ T919] [foliodbg] erofs_onlinefolio_end:358 EROFS FOLIO fffffdffc00420c0 PRIVATE BEFORE ffff000004442780
[ 684.642007][ T919] [foliodbg] dump_folio struct folio (00000000cf314425):
[ 684.642007][ T919] flags=0x1ff0000000004320
[ 684.642007][ T919] index=3392
[ 684.642007][ T919] private=ffff000004442780
[ 684.642007][ T919] mapcount=-1
[ 684.642007][ T919] refcount=3
[ 684.642007][ T919] memcg_data=0x0
[ 684.642007][ T919] flags_1=0x1ff0000000000000
[ 684.642007][ T919] head_1=0x0
[ 684.642007][ T919] large_mapcount=290
[ 684.642007][ T919] nr_pages_mapped=-559087616
[ 684.642007][ T919] entire_mapcount=0
[ 684.642007][ T919] pincount=0
[ 684.642007][ T919] mm_id_mapcount=[1102, 0]
[ 684.642007][ T919] mapcount_1=-1
[ 684.642007][ T919] refcount_1=1
[ 684.642007][ T919] nr_pages=14937858
[ 684.642007][ T919] flags_2=0x1ff0000000000000
[ 684.642007][ T919] head_2=0x0
[ 684.642007][ T919] flags_3=0x1ff0000000000000
[ 684.642007][ T919] head_3=0x0
[ 684.642007][ T919]
[ 684.744491][ T919] [foliodbg] dump_folio_page struct page (00000000cf314425):
[ 684.744491][ T919] flags=0x1ff0000000004320
[ 684.744491][ T919] index=3392
[ 684.744491][ T919] privat=0xffff000004442780
[ 684.744491][ T919] page_type(mapcount)=0xffffffff
[ 684.744491][ T919] memcg_data=0x0
[ 684.744491][ T919] refcount=3
[ 684.744491][ T919]
[ 684.779714][ T919] [foliodbg] dump_folio_address_space struct address_space (0000000000000000):
[ 684.779714][ T919] i_ino=0x0
[ 684.779714][ T919] s_dev=0x0
[ 684.779714][ T919] i_rdev=0x0
[ 684.779714][ T919] gfp_mask=0
[ 684.779714][ T919] i_mmap_writable=0
[ 684.779714][ T919] nrpages=0
[ 684.779714][ T919] writeback_index=0 flags=0x0
[ 684.779714][ T919] wb_err=0
[ 684.779714][ T919] i_private_data=0000000000000000
[ 684.779714][ T919]
[ 684.826573][ T919] folio private000000009ef9d99a: 5a 45 52 4f 46 53 50 43 00 00 00 00 00 00 00 00 ZEROFSPC........
[ 684.831621][ T919] folio private000000007d6aa995: 00 00 00 00 00 00 00 00 98 27 44 04 00 00 ff ff .........'D.....
[ 684.842031][ T919] CPU: 0 UID: 0 PID: 919 Comm: kworker/0:14H Tainted: G O 6.15.11-sdkernel #6 PREEMPT
[ 684.842056][ T919] Tainted: [O]=OOT_MODULE
[ 684.842076][ T919] Workqueue: kverityd verity_work
[ 684.842098][ T919] Call trace:
[ 684.842103][ T919] show_stack+0x18/0x30 (C)
[ 684.842123][ T919] dump_stack_lvl+0x60/0x80
[ 684.842138][ T919] dump_stack+0x18/0x24
[ 684.842156][ T919] erofs_onlinefolio_end+0x264/0x2b0
[ 684.842185][ T919] z_erofs_decompress_queue+0x4c0/0x8e0
[ 684.842211][ T919] z_erofs_decompress_kickoff+0x88/0x150
[ 684.842226][ T919] z_erofs_endio+0x144/0x250
[ 684.842246][ T919] bio_endio+0x138/0x150
[ 684.842266][ T919] __dm_io_complete+0x1e0/0x2b0
[ 684.842282][ T919] clone_endio+0xd0/0x270
[ 684.842302][ T919] bio_endio+0x138/0x150
[ 684.842322][ T919] verity_finish_io+0x64/0xf0
[ 684.842345][ T919] verity_work+0x30/0x40
[ 684.842355][ T919] process_one_work+0x180/0x2e0
[ 684.842375][ T919] worker_thread+0x2c4/0x3f0
[ 684.842394][ T919] kthread+0x12c/0x210
[ 684.842414][ T919] ret_from_fork+0x10/0x20
[ 684.842434][ T919]
[ 684.842434][ T919] [foliodbg] erofs_onlinefolio_end:371 EROFS FOLIO fffffdffc00420c0 PRIVATE SET ffff00002444277f
[ 684.958838][ T2486] ALSA: PCM: [Q] Lost interrupts?: (stream=1, delta=6576, new_hw_ptr=4943792, old_hw_ptr=4937216)
[ 684.969204][ T2485] ALSA: PCM: [Q] Lost interrupts?: (stream=1, delta=2352, new_hw_ptr=1646016, old_hw_ptr=1643664)
[ 685.015481][ T40] Unable to handle kernel paging request at virtual address ffff00002444277f
[ 685.021334][ T40] Mem abort info:
[ 685.021989][ T40] ESR = 0x0000000096000006
[ 685.026898][ T40] EC = 0x25: DABT (current EL), IL = 32 bits
[ 685.035918][ T40] SET = 0, FnV = 0
[ 685.035986][ T40] EA = 0, S1PTW = 0
[ 685.039855][ T40] FSC = 0x06: level 2 translation fault
[ 685.045343][ T40] Data abort info:
[ 685.049827][ T40] ISV = 0, ISS = 0x00000006, ISS2 = 0x00000000
[ 685.060195][ T40] CM = 0, WnR = 0, TnD = 0, TagAccess = 0
[ 685.060700][ T40] GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
[ 685.066643][ T40] swapper pgtable: 4k pages, 48-bit VAs, pgdp=0000000001e36000
[ 685.074075][ T40] [ffff00002444277f] pgd=1800000007fff403, p4d=1800000007fff403, pud=1800000007ffe403, pmd=0000000000000000
[ 685.086103][ T40] Internal error: Oops: 0000000096000006 [#1] SMP
[ 685.091448][ T40] Modules linked in: vlsicomm(O)
[ 685.092319][ T928]
[ 685.092319][ T928] [foliodbg] erofs_onlinefolio_end:358 EROFS FOLIO fffffdffc00420c0 PRIVATE BEFORE ffff00002444277f
[ 685.096180][ T40] CPU: 0 UID: 0 PID: 40 Comm: kswapd0 Tainted: G O 6.15.11-sdkernel #6 PREEMPT
[ 685.096194][ T40] Tainted: [O]=OOT_MODULE
[ 685.096199][ T40] Hardware name: SberDevices SberBoom Mini (DT)
[ 685.096205][ T40] pstate: 00400005 (nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[ 685.096214][ T40] pc : drop_buffers.constprop.0+0x34/0x120
[ 685.096233][ T40] lr : try_to_free_buffers+0xd0/0x100
[ 685.096244][ T40] sp : ffff800081063780
[ 685.096248][ T40] x29: ffff800081063780 x28: 0000000000000000 x27: fffffdffc00420c8
[ 685.096265][ T40] x26: ffff8000810638a0 x25: ffff800081063868 x24: 0000000000000001
[ 685.122584][ T928] [foliodbg] dump_folio struct folio (00000000cf314425):
[ 685.122584][ T928] flags=0x1ff0000000004201
[ 685.122584][ T928] index=3392
[ 685.122584][ T928] private=ffff00002444277f
[ 685.122584][ T928] mapcount=-1
[ 685.122584][ T928] refcount=4
[ 685.122584][ T928] memcg_data=0x0
[ 685.122584][ T928] flags_1=0x1ff0000000000000
[ 685.122584][ T928] head_1=0x0
[ 685.122584][ T928] large_mapcount=290
[ 685.122584][ T928] nr_pages_mapped=-559087616
[ 685.122584][ T928] entire_mapcount=0
[ 685.122584][ T928] pincount=0
[ 685.122584][ T928] mm_id_mapcount=[1102, 0]
[ 685.122584][ T928] mapcount_1=-1
[ 685.122584][ T928] refcount_1=1
[ 685.122584][ T928] nr_pages=14937858
[ 685.122584][ T928] flags_2=0x1ff0000000000000
[ 685.122584][ T928] head_2=0x0
[ 685.122584][ T928] flags_3=0x1ff0000000000000
[ 685.122584][ T928] head_3=0x0
[ 685.122584][ T928]
[ 685.123256][ T40]
[ 685.123259][ T40] x23: fffffdffc00420c0 x22: ffff8000810637b0 x21: fffffdffc00420c0
[ 685.123275][ T40] x20: ffff00002444277f x19: ffff00002444277f x18: 0000000000000000
[ 685.123290][ T40] x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000
[ 685.129416][ T928] [foliodbg] dump_folio_page struct page (00000000cf314425):
[ 685.129416][ T928] flags=0x1ff0000000004201
[ 685.129416][ T928] index=3392
[ 685.129416][ T928] privat=0xffff00002444277f
[ 685.129416][ T928] page_type(mapcount)=0xffffffff
[ 685.129416][ T928] memcg_data=0x0
[ 685.129416][ T928] refcount=4
[ 685.129416][ T928]
[ 685.136882][ T40] x14: ffff7fff87288000 x13: 00589f68e49c5358 x12: ffff800080d59b58
[ 685.136897][ T40] x11: 0000000000000002
[ 685.142500][ T928] [foliodbg] dump_folio_address_space struct address_space (0000000000000000):
[ 685.142500][ T928] i_ino=0x0
[ 685.142500][ T928] s_dev=0x0
[ 685.142500][ T928] i_rdev=0x0
[ 685.142500][ T928] gfp_mask=0
[ 685.142500][ T928] i_mmap_writable=0
[ 685.142500][ T928] nrpages=0
[ 685.142500][ T928] writeback_index=0 flags=0x0
[ 685.142500][ T928] wb_err=0
[ 685.142500][ T928] i_private_data=0000000000000000
[ 685.142500][ T928]
[ 685.147659][ T40] x10: ffff800081063770 x9 : 0000000000000001
[ 685.151841][ T928] Unable to handle kernel paging request at virtual address ffff00002444277f
[ 685.159394][ T40]
[ 685.159399][ T40] x8 : ffff8000810637d0 x7 : 0000000000000000 x6 : 0000000000000000
[ 685.167188][ T928] Mem abort info:
[ 685.248399][ T40]
[ 685.248406][ T40] x5 : 0000000000000000 x4 : fffffdffc00420c0 x3 : 1ff0000000004201
[ 685.248421][ T40] x2 : 1ff0000000004201
[ 685.252253][ T928] ESR = 0x0000000096000006
[ 685.258322][ T40] x1 : ffff8000810637b0 x0 : fffffdffc00420c0
[ 685.258335][ T40] Call trace:
[ 685.258340][ T40] drop_buffers.constprop.0+0x34/0x120 (P)
[ 685.258359][ T40] try_to_free_buffers+0xd0/0x100
[ 685.266380][ T928] EC = 0x25: DABT (current EL), IL = 32 bits
[ 685.273848][ T40] filemap_release_folio+0x94/0xc0
[ 685.273865][ T40] shrink_folio_list+0x8c8/0xc40
[ 685.306455][ T928] SET = 0, FnV = 0
[ 685.313609][ T40] shrink_lruvec+0x740/0xb80
[ 685.313624][ T40] shrink_node+0x2b8/0x9a0
[ 685.318050][ T928] EA = 0, S1PTW = 0
[ 685.359062][ T40] balance_pgdat+0x3b8/0x760
[ 685.359077][ T40] kswapd+0x220/0x3b0
[ 685.359096][ T40] kthread+0x12c/0x210
[ 685.359108][ T40] ret_from_fork+0x10/0x20
[ 685.359127][ T40] Code: 14000004 f9400673 eb13029f 54000180 (f9400262)
[ 685.359134][ T40] ---[ end trace 0000000000000000 ]---
[ 685.372682][ T40] Kernel panic - not syncing: Oops: Fatal exception
[ 685.372694][ T40] SMP: stopping secondary CPUs
[ 685.373561][ T40] Kernel Offset: disabled
[ 685.373565][ T40] CPU features: 0x0000,00000000,01000000,0200420b
[ 685.373576][ T40] Memory Limit: none


Thanks


>
> Thanks,
> Gao Xiang
>
>> +        pr_emerg("\n[foliodbg] %s:%d EROFS FOLIO %px PRIVATE BEFORE %px\n", __func__, __LINE__, folio, folio->private);
>> +        dump_stack();
>> +    }
>> +
>>       do {
>>           orig = atomic_read((atomic_t *)&folio->private);
>>           DBG_BUGON(orig <= 0);
>> @@ -245,6 +250,9 @@ void erofs_onlinefolio_end(struct folio *folio, int err, bool dirty)
>>           v |= (orig - 1) | (!!err << EROFS_ONLINEFOLIO_EIO);
>>       } while (atomic_cmpxchg((atomic_t *)&folio->private, orig, v) != orig);
>>   +    if (((uintptr_t)folio->private) & 0xffff000000000000)
>> +        pr_emerg("\n[foliodbg] %s:%d EROFS FOLIO %px PRIVATE SET %px\n", __func__, __LINE__, folio, folio->private);
>> +
>>       if (v & (BIT(EROFS_ONLINEFOLIO_DIRTY) - 1))
>>           return;
>>       folio->private = 0;
>>
>>
>> And it gives result:
>>
>> [][  T639] [foliodbg] erofs_onlinefolio_end:242 EROFS FOLIO fffffdffc0030440 PRIVATE BEFORE ffff000002b32468
>> [][  T639] CPU: 0 UID: 0 PID: 639 Comm: kworker/0:6H Tainted: G O 6.15.11-sdkernel #1 PREEMPT
>> [][  T639] Tainted: [O]=OOT_MODULE
>> [][  T639] Workqueue: kverityd verity_work
>> [][  T639] Call trace:
>> [][  T639]  show_stack+0x18/0x30 (C)
>> [][  T639]  dump_stack_lvl+0x60/0x80
>> [][  T639]  dump_stack+0x18/0x24
>> [][  T639]  erofs_onlinefolio_end+0x124/0x130
>> [][  T639]  z_erofs_decompress_queue+0x4b0/0x8c0
>> [][  T639]  z_erofs_decompress_kickoff+0x88/0x150
>> [][  T639]  z_erofs_endio+0x144/0x250
>> [][  T639]  bio_endio+0x138/0x150
>> [][  T639]  __dm_io_complete+0x1e0/0x2b0
>> [][  T639]  clone_endio+0xd0/0x270
>> [][  T639]  bio_endio+0x138/0x150
>> [][  T639]  verity_finish_io+0x64/0xf0
>> [][  T639]  verity_work+0x30/0x40
>> [][  T639]  process_one_work+0x180/0x2e0
>> [][  T639]  worker_thread+0x2c4/0x3f0
>> [][  T639]  kthread+0x12c/0x210
>> [][  T639]  ret_from_fork+0x10/0x20
>> [][  T639]
>> [][  T639] [foliodbg] erofs_onlinefolio_end:254 EROFS FOLIO fffffdffc0030440 PRIVATE SET ffff000022b32467
>> [][   T39] Unable to handle kernel paging request at virtual address ffff000022b32467
>> [][   T39] Mem abort info:
>> [][   T39]   ESR = 0x0000000096000006
>> [][   T39]   EC = 0x25: DABT (current EL), IL = 32 bits
>> [][   T39]   SET = 0, FnV = 0
>> [][   T39]   EA = 0, S1PTW = 0
>> [][   T39]   FSC = 0x06: level 2 translation fault
>> [][   T39] Data abort info:
>> [][   T39]   ISV = 0, ISS = 0x00000006, ISS2 = 0x00000000
>> [][   T39]   CM = 0, WnR = 0, TnD = 0, TagAccess = 0
>> [][   T39]   GCS = 0, Overlay = 0, DirtyBit = 0, Xs = 0
>> [][   T39] swapper pgtable: 4k pages, 48-bit VAs, pgdp=0000000001e36000
>> [][   T39] [ffff000022b32467] pgd=1800000007fff403, p4d=1800000007fff403, pud=1800000007ffe403, pmd=0000000000000000
>> [][   T39] Internal error: Oops: 0000000096000006 [#1]  SMP
>> [][   T39] Modules linked in: vlsicomm(O)
>> [][   T39] CPU: 1 UID: 0 PID: 39 Comm: kswapd0 Tainted: G O 6.15.11-sdkernel #1 PREEMPT
>> [][   T39] Tainted: [O]=OOT_MODULE
>> [][   T39] pstate: 00400005 (nzcv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
>> [][   T39] pc : drop_buffers.constprop.0+0x34/0x120
>> [][   T39] lr : try_to_free_buffers+0xd0/0x100
>> [][   T39] sp : ffff80008105b780
>> [][   T39] x29: ffff80008105b780 x28: 0000000000000000 x27: fffffdffc0030448
>> [][   T39] x26: ffff80008105b8a0 x25: ffff80008105b868 x24: 0000000000000001
>> [][   T39] x23: fffffdffc0030440 x22: ffff80008105b7b0 x21: fffffdffc0030440
>> [][   T39] x20: ffff000022b32467 x19: ffff000022b32467 x18: 0000000000000000
>> [][   T39] x17: 0000000000000000 x16: 0000000000000000 x15: 00000000d69f4cc0
>> [][   T39] x14: ffff0000000c5dc0 x13: 0000000000000000 x12: ffff800080d59b58
>> [][   T39] x11: 00000000000000c0 x10: 0000000000000000 x9 : 0000000000000000
>> [][   T39] x8 : ffff80008105b7d0 x7 : 0000000000000000 x6 : 000000000000003f
>> [][   T39] x5 : 0000000000000000 x4 : fffffdffc0030440 x3 : 1ff0000000004001
>> [][   T39] x2 : 1ff0000000004001 x1 : ffff80008105b7b0 x0 : fffffdffc0030440
>> [][   T39] Call trace:
>> [][   T39]  drop_buffers.constprop.0+0x34/0x120 (P)
>> [][   T39]  try_to_free_buffers+0xd0/0x100
>> [][   T39]  filemap_release_folio+0x94/0xc0
>> [][   T39]  shrink_folio_list+0x8c8/0xc40
>> [][   T39]  shrink_lruvec+0x740/0xb80
>> [][   T39]  shrink_node+0x2b8/0x9a0
>> [][   T39]  balance_pgdat+0x3b8/0x760
>> [][   T39]  kswapd+0x220/0x3b0
>> [][   T39]  kthread+0x12c/0x210
>> [][   T39]  ret_from_fork+0x10/0x20
>> [][   T39] Code: 14000004 f9400673 eb13029f 54000180 (f9400262)
>> [][   T39] ---[ end trace 0000000000000000 ]---
>> [][   T39] Kernel panic - not syncing: Oops: Fatal exception
>> [][   T39] SMP: stopping secondary CPUs
>> [][   T39] Kernel Offset: disabled
>> [][   T39] CPU features: 0x0000,00000000,01000000,0200420b
>> [][   T39] Memory Limit: none
>> [][   T39] Rebooting in 5 seconds..
>>
>> So 'erofs_onlinefolio_end()' takes some folio with 'private' field contains
>> some pointer (0xffff000002b32468), "corrupts" this pointer (result will be
>> 0xffff000022b32467 - at least we see that 0x20000000 was ORed to original
>> pointer and this is (1 << EROFS_ONLINEFOLIO_DIRTY)), and then kernel crashes.
>> We guess it is not valid case when such folio is passed as argument to
>> 'erofs_onlinefolio_end()'.
>>
>> We have the following erofs configuration in buildroot:
>>
>> BR2_TARGET_ROOTFS_EROFS=y
>> BR2_TARGET_ROOTFS_EROFS_CUSTOM_COMPRESSION=y
>> BR2_TARGET_ROOTFS_EROFS_COMPRESSION_ALGORITHMS="zstd,22 --max-extent-bytes 65536 -E48bit"
>> BR2_TARGET_ROOTFS_EROFS_FRAGMENTS=y
>> BR2_TARGET_ROOTFS_EROFS_PCLUSTERSIZE=65536
>>
>>
>>
>> May be You know how to fix it or some ideas? Because we are new at erofs and need to discover and
>> learn its source code.
>>
>> Thanks
>