Skip to content

Commit 35076d2

Browse files
committed
erofs: ensure the extra temporary copy is valid for shortened bvecs
When compressed data deduplication is enabled, multiple logical extents may reference the same compressed physical cluster. The previous commit 94c43de ("erofs: fix wrong primary bvec selection on deduplicated extents") already avoids using shortened bvecs. However, in such cases, the extra temporary buffers also need to be preserved for later use in z_erofs_fill_other_copies() to to prevent data corruption. IOWs, extra temporary buffers have to be retained not only due to varying start relative offsets (`pageofs_out`, as indicated by `pcl->multibases`) but also because of shortened bvecs. android.hardware.graphics.composer@2.1.so : 270696 bytes 0: 0.. 204185 | 204185 : 628019200.. 628084736 | 65536 -> 1: 204185.. 225536 | 21351 : 544063488.. 544129024 | 65536 2: 225536.. 270696 | 45160 : 0.. 0 | 0 com.android.vndk.v28.apex : 93814897 bytes ... 364: 53869896..54095257 | 225361 : 543997952.. 544063488 | 65536 -> 365: 54095257..54309344 | 214087 : 544063488.. 544129024 | 65536 366: 54309344..54514557 | 205213 : 544129024.. 544194560 | 65536 ... Both 204185 and 54095257 have the same start relative offset of 3481, but the logical page 55 of `android.hardware.graphics.composer@2.1.so` ranges from 225280 to 229632, forming a shortened bvec [225280, 225536) that cannot be used for decompressing the range from 54095257 to 54309344 of `com.android.vndk.v28.apex`. Since `pcl->multibases` is already meaningless, just mark `be->keepxcpy` on demand for simplicity. Again, this issue can only lead to data corruption if `-Ededupe` is on. Fixes: 94c43de ("erofs: fix wrong primary bvec selection on deduplicated extents") Reviewed-by: Hongbo Li <lihongbo22@huawei.com> Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com> Link: https://lore.kernel.org/r/20250506101850.191506-1-hsiangkao@linux.alibaba.com
1 parent 9fcd53c commit 35076d2

File tree

1 file changed

+14
-17
lines changed

1 file changed

+14
-17
lines changed

fs/erofs/zdata.c

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,6 @@ struct z_erofs_pcluster {
7979
/* L: whether partial decompression or not */
8080
bool partial;
8181

82-
/* L: indicate several pageofs_outs or not */
83-
bool multibases;
84-
8582
/* L: whether extra buffer allocations are best-effort */
8683
bool besteffort;
8784

@@ -1046,8 +1043,6 @@ static int z_erofs_scan_folio(struct z_erofs_frontend *f,
10461043
break;
10471044

10481045
erofs_onlinefolio_split(folio);
1049-
if (f->pcl->pageofs_out != (map->m_la & ~PAGE_MASK))
1050-
f->pcl->multibases = true;
10511046
if (f->pcl->length < offset + end - map->m_la) {
10521047
f->pcl->length = offset + end - map->m_la;
10531048
f->pcl->pageofs_out = map->m_la & ~PAGE_MASK;
@@ -1093,7 +1088,6 @@ struct z_erofs_backend {
10931088
struct page *onstack_pages[Z_EROFS_ONSTACK_PAGES];
10941089
struct super_block *sb;
10951090
struct z_erofs_pcluster *pcl;
1096-
10971091
/* pages with the longest decompressed length for deduplication */
10981092
struct page **decompressed_pages;
10991093
/* pages to keep the compressed data */
@@ -1102,6 +1096,8 @@ struct z_erofs_backend {
11021096
struct list_head decompressed_secondary_bvecs;
11031097
struct page **pagepool;
11041098
unsigned int onstack_used, nr_pages;
1099+
/* indicate if temporary copies should be preserved for later use */
1100+
bool keepxcpy;
11051101
};
11061102

11071103
struct z_erofs_bvec_item {
@@ -1112,18 +1108,20 @@ struct z_erofs_bvec_item {
11121108
static void z_erofs_do_decompressed_bvec(struct z_erofs_backend *be,
11131109
struct z_erofs_bvec *bvec)
11141110
{
1111+
int poff = bvec->offset + be->pcl->pageofs_out;
11151112
struct z_erofs_bvec_item *item;
1116-
unsigned int pgnr;
1117-
1118-
if (!((bvec->offset + be->pcl->pageofs_out) & ~PAGE_MASK) &&
1119-
(bvec->end == PAGE_SIZE ||
1120-
bvec->offset + bvec->end == be->pcl->length)) {
1121-
pgnr = (bvec->offset + be->pcl->pageofs_out) >> PAGE_SHIFT;
1122-
DBG_BUGON(pgnr >= be->nr_pages);
1123-
if (!be->decompressed_pages[pgnr]) {
1124-
be->decompressed_pages[pgnr] = bvec->page;
1113+
struct page **page;
1114+
1115+
if (!(poff & ~PAGE_MASK) && (bvec->end == PAGE_SIZE ||
1116+
bvec->offset + bvec->end == be->pcl->length)) {
1117+
DBG_BUGON((poff >> PAGE_SHIFT) >= be->nr_pages);
1118+
page = be->decompressed_pages + (poff >> PAGE_SHIFT);
1119+
if (!*page) {
1120+
*page = bvec->page;
11251121
return;
11261122
}
1123+
} else {
1124+
be->keepxcpy = true;
11271125
}
11281126

11291127
/* (cold path) one pcluster is requested multiple times */
@@ -1289,7 +1287,7 @@ static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, int err)
12891287
.alg = pcl->algorithmformat,
12901288
.inplace_io = overlapped,
12911289
.partial_decoding = pcl->partial,
1292-
.fillgaps = pcl->multibases,
1290+
.fillgaps = be->keepxcpy,
12931291
.gfp = pcl->besteffort ? GFP_KERNEL :
12941292
GFP_NOWAIT | __GFP_NORETRY
12951293
}, be->pagepool);
@@ -1346,7 +1344,6 @@ static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, int err)
13461344

13471345
pcl->length = 0;
13481346
pcl->partial = true;
1349-
pcl->multibases = false;
13501347
pcl->besteffort = false;
13511348
pcl->bvset.nextpage = NULL;
13521349
pcl->vcnt = 0;

0 commit comments

Comments
 (0)