Skip to content

Commit 3e2059c

Browse files
hsiangkaoSasha Levin
authored andcommitted
erofs: ensure the extra temporary copy is valid for shortened bvecs
[ Upstream commit 35076d2 ] 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 Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 4573e98 commit 3e2059c

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
@@ -82,9 +82,6 @@ struct z_erofs_pcluster {
8282
/* L: whether partial decompression or not */
8383
bool partial;
8484

85-
/* L: indicate several pageofs_outs or not */
86-
bool multibases;
87-
8885
/* L: whether extra buffer allocations are best-effort */
8986
bool besteffort;
9087

@@ -1073,8 +1070,6 @@ static int z_erofs_scan_folio(struct z_erofs_decompress_frontend *f,
10731070
break;
10741071

10751072
erofs_onlinefolio_split(folio);
1076-
if (f->pcl->pageofs_out != (map->m_la & ~PAGE_MASK))
1077-
f->pcl->multibases = true;
10781073
if (f->pcl->length < offset + end - map->m_la) {
10791074
f->pcl->length = offset + end - map->m_la;
10801075
f->pcl->pageofs_out = map->m_la & ~PAGE_MASK;
@@ -1120,7 +1115,6 @@ struct z_erofs_decompress_backend {
11201115
struct page *onstack_pages[Z_EROFS_ONSTACK_PAGES];
11211116
struct super_block *sb;
11221117
struct z_erofs_pcluster *pcl;
1123-
11241118
/* pages with the longest decompressed length for deduplication */
11251119
struct page **decompressed_pages;
11261120
/* pages to keep the compressed data */
@@ -1129,6 +1123,8 @@ struct z_erofs_decompress_backend {
11291123
struct list_head decompressed_secondary_bvecs;
11301124
struct page **pagepool;
11311125
unsigned int onstack_used, nr_pages;
1126+
/* indicate if temporary copies should be preserved for later use */
1127+
bool keepxcpy;
11321128
};
11331129

11341130
struct z_erofs_bvec_item {
@@ -1139,18 +1135,20 @@ struct z_erofs_bvec_item {
11391135
static void z_erofs_do_decompressed_bvec(struct z_erofs_decompress_backend *be,
11401136
struct z_erofs_bvec *bvec)
11411137
{
1138+
int poff = bvec->offset + be->pcl->pageofs_out;
11421139
struct z_erofs_bvec_item *item;
1143-
unsigned int pgnr;
1144-
1145-
if (!((bvec->offset + be->pcl->pageofs_out) & ~PAGE_MASK) &&
1146-
(bvec->end == PAGE_SIZE ||
1147-
bvec->offset + bvec->end == be->pcl->length)) {
1148-
pgnr = (bvec->offset + be->pcl->pageofs_out) >> PAGE_SHIFT;
1149-
DBG_BUGON(pgnr >= be->nr_pages);
1150-
if (!be->decompressed_pages[pgnr]) {
1151-
be->decompressed_pages[pgnr] = bvec->page;
1140+
struct page **page;
1141+
1142+
if (!(poff & ~PAGE_MASK) && (bvec->end == PAGE_SIZE ||
1143+
bvec->offset + bvec->end == be->pcl->length)) {
1144+
DBG_BUGON((poff >> PAGE_SHIFT) >= be->nr_pages);
1145+
page = be->decompressed_pages + (poff >> PAGE_SHIFT);
1146+
if (!*page) {
1147+
*page = bvec->page;
11521148
return;
11531149
}
1150+
} else {
1151+
be->keepxcpy = true;
11541152
}
11551153

11561154
/* (cold path) one pcluster is requested multiple times */
@@ -1316,7 +1314,7 @@ static int z_erofs_decompress_pcluster(struct z_erofs_decompress_backend *be,
13161314
.alg = pcl->algorithmformat,
13171315
.inplace_io = overlapped,
13181316
.partial_decoding = pcl->partial,
1319-
.fillgaps = pcl->multibases,
1317+
.fillgaps = be->keepxcpy,
13201318
.gfp = pcl->besteffort ? GFP_KERNEL :
13211319
GFP_NOWAIT | __GFP_NORETRY
13221320
}, be->pagepool);
@@ -1370,7 +1368,6 @@ static int z_erofs_decompress_pcluster(struct z_erofs_decompress_backend *be,
13701368

13711369
pcl->length = 0;
13721370
pcl->partial = true;
1373-
pcl->multibases = false;
13741371
pcl->besteffort = false;
13751372
pcl->bvset.nextpage = NULL;
13761373
pcl->vcnt = 0;

0 commit comments

Comments
 (0)