Skip to content

Commit 92a9392

Browse files
hsiangkaosmb49
authored andcommitted
erofs: ensure the extra temporary copy is valid for shortened bvecs
BugLink: https://bugs.launchpad.net/bugs/2115252 [ 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. [email protected] : 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 `[email protected]` 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 <[email protected]> Signed-off-by: Gao Xiang <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Sasha Levin <[email protected]> Signed-off-by: Manuel Diewald <[email protected]> Signed-off-by: Stefan Bader <[email protected]>
1 parent 539d7e6 commit 92a9392

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
@@ -76,9 +76,6 @@ struct z_erofs_pcluster {
7676
/* L: whether partial decompression or not */
7777
bool partial;
7878

79-
/* L: indicate several pageofs_outs or not */
80-
bool multibases;
81-
8279
/* L: whether extra buffer allocations are best-effort */
8380
bool besteffort;
8481

@@ -1050,8 +1047,6 @@ static int z_erofs_scan_folio(struct z_erofs_frontend *f,
10501047
break;
10511048

10521049
erofs_onlinefolio_split(folio);
1053-
if (f->pcl->pageofs_out != (map->m_la & ~PAGE_MASK))
1054-
f->pcl->multibases = true;
10551050
if (f->pcl->length < offset + end - map->m_la) {
10561051
f->pcl->length = offset + end - map->m_la;
10571052
f->pcl->pageofs_out = map->m_la & ~PAGE_MASK;
@@ -1097,7 +1092,6 @@ struct z_erofs_backend {
10971092
struct page *onstack_pages[Z_EROFS_ONSTACK_PAGES];
10981093
struct super_block *sb;
10991094
struct z_erofs_pcluster *pcl;
1100-
11011095
/* pages with the longest decompressed length for deduplication */
11021096
struct page **decompressed_pages;
11031097
/* pages to keep the compressed data */
@@ -1106,6 +1100,8 @@ struct z_erofs_backend {
11061100
struct list_head decompressed_secondary_bvecs;
11071101
struct page **pagepool;
11081102
unsigned int onstack_used, nr_pages;
1103+
/* indicate if temporary copies should be preserved for later use */
1104+
bool keepxcpy;
11091105
};
11101106

11111107
struct z_erofs_bvec_item {
@@ -1116,18 +1112,20 @@ struct z_erofs_bvec_item {
11161112
static void z_erofs_do_decompressed_bvec(struct z_erofs_backend *be,
11171113
struct z_erofs_bvec *bvec)
11181114
{
1115+
int poff = bvec->offset + be->pcl->pageofs_out;
11191116
struct z_erofs_bvec_item *item;
1120-
unsigned int pgnr;
1121-
1122-
if (!((bvec->offset + be->pcl->pageofs_out) & ~PAGE_MASK) &&
1123-
(bvec->end == PAGE_SIZE ||
1124-
bvec->offset + bvec->end == be->pcl->length)) {
1125-
pgnr = (bvec->offset + be->pcl->pageofs_out) >> PAGE_SHIFT;
1126-
DBG_BUGON(pgnr >= be->nr_pages);
1127-
if (!be->decompressed_pages[pgnr]) {
1128-
be->decompressed_pages[pgnr] = bvec->page;
1117+
struct page **page;
1118+
1119+
if (!(poff & ~PAGE_MASK) && (bvec->end == PAGE_SIZE ||
1120+
bvec->offset + bvec->end == be->pcl->length)) {
1121+
DBG_BUGON((poff >> PAGE_SHIFT) >= be->nr_pages);
1122+
page = be->decompressed_pages + (poff >> PAGE_SHIFT);
1123+
if (!*page) {
1124+
*page = bvec->page;
11291125
return;
11301126
}
1127+
} else {
1128+
be->keepxcpy = true;
11311129
}
11321130

11331131
/* (cold path) one pcluster is requested multiple times */
@@ -1291,7 +1289,7 @@ static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, int err)
12911289
.alg = pcl->algorithmformat,
12921290
.inplace_io = overlapped,
12931291
.partial_decoding = pcl->partial,
1294-
.fillgaps = pcl->multibases,
1292+
.fillgaps = be->keepxcpy,
12951293
.gfp = pcl->besteffort ? GFP_KERNEL :
12961294
GFP_NOWAIT | __GFP_NORETRY
12971295
}, be->pagepool);
@@ -1348,7 +1346,6 @@ static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, int err)
13481346

13491347
pcl->length = 0;
13501348
pcl->partial = true;
1351-
pcl->multibases = false;
13521349
pcl->besteffort = false;
13531350
pcl->bvset.nextpage = NULL;
13541351
pcl->vcnt = 0;

0 commit comments

Comments
 (0)