Skip to content

Commit d928166

Browse files
Chunhai Guohsiangkao
authored andcommitted
erofs: relaxed temporary buffers allocation on readahead
Even with inplace decompression, sometimes very few temporary buffers may be still needed for a single decompression shot (e.g. 16 pages for 64k sliding window or 4 pages for 16k sliding window). In low-memory scenarios, it would be better to try to allocate with GFP_NOWAIT on readahead first. That can help reduce the time spent on page allocation under durative memory pressure. Here are detailed performance numbers under multi-app launch benchmark workload [1] on ARM64 Android devices (8-core CPU and 8GB of memory) running a 5.15 LTS kernel with EROFS of 4k pclusters: +----------------------------------------------+ | LZ4 | vanilla | patched | diff | |----------------+---------+---------+---------| | Average (ms) | 3364 | 2684 | -20.21% | [64k sliding window] |----------------+---------+---------+---------| | Average (ms) | 2079 | 1610 | -22.56% | [16k sliding window] +----------------------------------------------+ The total size of system images for 4k pclusters is almost unchanged: (64k sliding window) 9,117,044 KB (16k sliding window) 9,113,096 KB Therefore, in addition to switch the sliding window from 64k to 16k, after applying this patch, it can eventually save 52.14% (3364 -> 1610) on average with no memory reservation. That is particularly useful for embedded devices with limited resources. [1] https://lore.kernel.org/r/[email protected] Suggested-by: Gao Xiang <[email protected]> Signed-off-by: Chunhai Guo <[email protected]> Signed-off-by: Gao Xiang <[email protected]> Reviewed-by: Yue Hu <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent cc4b2dd commit d928166

File tree

5 files changed

+42
-20
lines changed

5 files changed

+42
-20
lines changed

fs/erofs/compress.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,12 @@
1111
struct z_erofs_decompress_req {
1212
struct super_block *sb;
1313
struct page **in, **out;
14-
1514
unsigned short pageofs_in, pageofs_out;
1615
unsigned int inputsize, outputsize;
1716

18-
/* indicate the algorithm will be used for decompression */
19-
unsigned int alg;
17+
unsigned int alg; /* the algorithm for decompression */
2018
bool inplace_io, partial_decoding, fillgaps;
19+
gfp_t gfp; /* allocation flags for extra temporary buffers */
2120
};
2221

2322
struct z_erofs_decompressor {

fs/erofs/decompressor.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,9 @@ static int z_erofs_lz4_prepare_dstpages(struct z_erofs_lz4_decompress_ctx *ctx,
111111
victim = availables[--top];
112112
get_page(victim);
113113
} else {
114-
victim = erofs_allocpage(pagepool,
115-
GFP_KERNEL | __GFP_NOFAIL);
114+
victim = erofs_allocpage(pagepool, rq->gfp);
115+
if (!victim)
116+
return -ENOMEM;
116117
set_page_private(victim, Z_EROFS_SHORTLIVED_PAGE);
117118
}
118119
rq->out[i] = victim;

fs/erofs/decompressor_deflate.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ int z_erofs_load_deflate_config(struct super_block *sb,
9595
}
9696

9797
int z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
98-
struct page **pagepool)
98+
struct page **pgpl)
9999
{
100100
const unsigned int nrpages_out =
101101
PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT;
@@ -158,8 +158,12 @@ int z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
158158
strm->z.avail_out = min_t(u32, outsz, PAGE_SIZE - pofs);
159159
outsz -= strm->z.avail_out;
160160
if (!rq->out[no]) {
161-
rq->out[no] = erofs_allocpage(pagepool,
162-
GFP_KERNEL | __GFP_NOFAIL);
161+
rq->out[no] = erofs_allocpage(pgpl, rq->gfp);
162+
if (!rq->out[no]) {
163+
kout = NULL;
164+
err = -ENOMEM;
165+
break;
166+
}
163167
set_page_private(rq->out[no],
164168
Z_EROFS_SHORTLIVED_PAGE);
165169
}
@@ -211,8 +215,11 @@ int z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
211215

212216
DBG_BUGON(erofs_page_is_managed(EROFS_SB(sb),
213217
rq->in[j]));
214-
tmppage = erofs_allocpage(pagepool,
215-
GFP_KERNEL | __GFP_NOFAIL);
218+
tmppage = erofs_allocpage(pgpl, rq->gfp);
219+
if (!tmppage) {
220+
err = -ENOMEM;
221+
goto failed;
222+
}
216223
set_page_private(tmppage, Z_EROFS_SHORTLIVED_PAGE);
217224
copy_highpage(tmppage, rq->in[j]);
218225
rq->in[j] = tmppage;
@@ -230,7 +237,7 @@ int z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
230237
break;
231238
}
232239
}
233-
240+
failed:
234241
if (zlib_inflateEnd(&strm->z) != Z_OK && !err)
235242
err = -EIO;
236243
if (kout)

fs/erofs/decompressor_lzma.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ int z_erofs_load_lzma_config(struct super_block *sb,
148148
}
149149

150150
int z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq,
151-
struct page **pagepool)
151+
struct page **pgpl)
152152
{
153153
const unsigned int nrpages_out =
154154
PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT;
@@ -215,8 +215,11 @@ int z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq,
215215
PAGE_SIZE - pageofs);
216216
outlen -= strm->buf.out_size;
217217
if (!rq->out[no] && rq->fillgaps) { /* deduped */
218-
rq->out[no] = erofs_allocpage(pagepool,
219-
GFP_KERNEL | __GFP_NOFAIL);
218+
rq->out[no] = erofs_allocpage(pgpl, rq->gfp);
219+
if (!rq->out[no]) {
220+
err = -ENOMEM;
221+
break;
222+
}
220223
set_page_private(rq->out[no],
221224
Z_EROFS_SHORTLIVED_PAGE);
222225
}
@@ -258,8 +261,11 @@ int z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq,
258261

259262
DBG_BUGON(erofs_page_is_managed(EROFS_SB(rq->sb),
260263
rq->in[j]));
261-
tmppage = erofs_allocpage(pagepool,
262-
GFP_KERNEL | __GFP_NOFAIL);
264+
tmppage = erofs_allocpage(pgpl, rq->gfp);
265+
if (!tmppage) {
266+
err = -ENOMEM;
267+
goto failed;
268+
}
263269
set_page_private(tmppage, Z_EROFS_SHORTLIVED_PAGE);
264270
copy_highpage(tmppage, rq->in[j]);
265271
rq->in[j] = tmppage;
@@ -277,6 +283,7 @@ int z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq,
277283
break;
278284
}
279285
}
286+
failed:
280287
if (no < nrpages_out && strm->buf.out)
281288
kunmap(rq->out[no]);
282289
if (ni < nrpages_in)

fs/erofs/zdata.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ struct z_erofs_pcluster {
8282
/* L: indicate several pageofs_outs or not */
8383
bool multibases;
8484

85+
/* L: whether extra buffer allocations are best-effort */
86+
bool besteffort;
87+
8588
/* A: compressed bvecs (can be cached or inplaced pages) */
8689
struct z_erofs_bvec compressed_bvecs[];
8790
};
@@ -960,7 +963,7 @@ static int z_erofs_read_fragment(struct super_block *sb, struct page *page,
960963
}
961964

962965
static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe,
963-
struct page *page)
966+
struct page *page, bool ra)
964967
{
965968
struct inode *const inode = fe->inode;
966969
struct erofs_map_blocks *const map = &fe->map;
@@ -1010,6 +1013,7 @@ static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe,
10101013
err = z_erofs_pcluster_begin(fe);
10111014
if (err)
10121015
goto out;
1016+
fe->pcl->besteffort |= !ra;
10131017
}
10141018

10151019
/*
@@ -1276,6 +1280,9 @@ static int z_erofs_decompress_pcluster(struct z_erofs_decompress_backend *be,
12761280
.inplace_io = overlapped,
12771281
.partial_decoding = pcl->partial,
12781282
.fillgaps = pcl->multibases,
1283+
.gfp = pcl->besteffort ?
1284+
GFP_KERNEL | __GFP_NOFAIL :
1285+
GFP_NOWAIT | __GFP_NORETRY
12791286
}, be->pagepool);
12801287

12811288
/* must handle all compressed pages before actual file pages */
@@ -1318,6 +1325,7 @@ static int z_erofs_decompress_pcluster(struct z_erofs_decompress_backend *be,
13181325
pcl->length = 0;
13191326
pcl->partial = true;
13201327
pcl->multibases = false;
1328+
pcl->besteffort = false;
13211329
pcl->bvset.nextpage = NULL;
13221330
pcl->vcnt = 0;
13231331

@@ -1787,7 +1795,7 @@ static void z_erofs_pcluster_readmore(struct z_erofs_decompress_frontend *f,
17871795
if (PageUptodate(page))
17881796
unlock_page(page);
17891797
else
1790-
(void)z_erofs_do_read_page(f, page);
1798+
(void)z_erofs_do_read_page(f, page, !!rac);
17911799
put_page(page);
17921800
}
17931801

@@ -1808,7 +1816,7 @@ static int z_erofs_read_folio(struct file *file, struct folio *folio)
18081816
f.headoffset = (erofs_off_t)folio->index << PAGE_SHIFT;
18091817

18101818
z_erofs_pcluster_readmore(&f, NULL, true);
1811-
err = z_erofs_do_read_page(&f, &folio->page);
1819+
err = z_erofs_do_read_page(&f, &folio->page, false);
18121820
z_erofs_pcluster_readmore(&f, NULL, false);
18131821
z_erofs_pcluster_end(&f);
18141822

@@ -1849,7 +1857,7 @@ static void z_erofs_readahead(struct readahead_control *rac)
18491857
folio = head;
18501858
head = folio_get_private(folio);
18511859

1852-
err = z_erofs_do_read_page(&f, &folio->page);
1860+
err = z_erofs_do_read_page(&f, &folio->page, true);
18531861
if (err && err != -EINTR)
18541862
erofs_err(inode->i_sb, "readahead error at folio %lu @ nid %llu",
18551863
folio->index, EROFS_I(inode)->nid);

0 commit comments

Comments
 (0)