Skip to content

Commit 586f14a

Browse files
committed
Merge tag 'erofs-for-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs
Pull erofs updates from Gao Xiang: "Updates for folio conversions for compressed inodes: While large folio support for compressed data could work now, it remains disabled since the stress test could hang due to page migration in a few hours after enabling it. I need more time to investigate further before enabling this feature. Additionally, clean up stream decompressors and tracepoints for simplicity. Summary: - More folio conversions for compressed inodes - Stream decompressor (LZMA/DEFLATE/ZSTD) cleanups - Minor tracepoint cleanup" * tag 'erofs-for-6.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs: erofs: silence uninitialized variable warning in z_erofs_scan_folio() erofs: avoid refcounting short-lived pages erofs: get rid of z_erofs_map_blocks_iter_* tracepoints erofs: tidy up stream decompressors erofs: refine z_erofs_{init,exit}_subsystem() erofs: move each decompressor to its own source file erofs: tidy up `struct z_erofs_bvec` erofs: teach z_erofs_scan_folios() to handle multi-page folios erofs: convert z_erofs_read_fragment() to folios erofs: convert z_erofs_pcluster_readmore() to folios
2 parents 586a7a8 + a3c10be commit 586f14a

File tree

10 files changed

+496
-646
lines changed

10 files changed

+496
-646
lines changed

fs/erofs/compress.h

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ struct z_erofs_decompressor {
2424
void *data, int size);
2525
int (*decompress)(struct z_erofs_decompress_req *rq,
2626
struct page **pagepool);
27+
int (*init)(void);
28+
void (*exit)(void);
2729
char *name;
2830
};
2931

@@ -52,50 +54,47 @@ struct z_erofs_decompressor {
5254
*/
5355

5456
/*
55-
* short-lived pages are pages directly from buddy system with specific
56-
* page->private (no need to set PagePrivate since these are non-LRU /
57-
* non-movable pages and bypass reclaim / migration code).
57+
* Currently, short-lived pages are pages directly from buddy system
58+
* with specific page->private (Z_EROFS_SHORTLIVED_PAGE).
59+
* In the future world of Memdescs, it should be type 0 (Misc) memory
60+
* which type can be checked with a new helper.
5861
*/
5962
static inline bool z_erofs_is_shortlived_page(struct page *page)
6063
{
61-
if (page->private != Z_EROFS_SHORTLIVED_PAGE)
62-
return false;
63-
64-
DBG_BUGON(page->mapping);
65-
return true;
64+
return page->private == Z_EROFS_SHORTLIVED_PAGE;
6665
}
6766

6867
static inline bool z_erofs_put_shortlivedpage(struct page **pagepool,
6968
struct page *page)
7069
{
7170
if (!z_erofs_is_shortlived_page(page))
7271
return false;
73-
74-
/* short-lived pages should not be used by others at the same time */
75-
if (page_ref_count(page) > 1) {
76-
put_page(page);
77-
} else {
78-
/* follow the pcluster rule above. */
79-
erofs_pagepool_add(pagepool, page);
80-
}
72+
erofs_pagepool_add(pagepool, page);
8173
return true;
8274
}
8375

76+
extern const struct z_erofs_decompressor z_erofs_lzma_decomp;
77+
extern const struct z_erofs_decompressor z_erofs_deflate_decomp;
78+
extern const struct z_erofs_decompressor z_erofs_zstd_decomp;
79+
extern const struct z_erofs_decompressor *z_erofs_decomp[];
80+
81+
struct z_erofs_stream_dctx {
82+
struct z_erofs_decompress_req *rq;
83+
unsigned int inpages, outpages; /* # of {en,de}coded pages */
84+
int no, ni; /* the current {en,de}coded page # */
85+
86+
unsigned int avail_out; /* remaining bytes in the decoded buffer */
87+
unsigned int inbuf_pos, inbuf_sz;
88+
/* current status of the encoded buffer */
89+
u8 *kin, *kout; /* buffer mapped pointers */
90+
void *bounce; /* bounce buffer for inplace I/Os */
91+
bool bounced; /* is the bounce buffer used now? */
92+
};
93+
94+
int z_erofs_stream_switch_bufs(struct z_erofs_stream_dctx *dctx, void **dst,
95+
void **src, struct page **pgpl);
8496
int z_erofs_fixup_insize(struct z_erofs_decompress_req *rq, const char *padbuf,
8597
unsigned int padbufsize);
86-
extern const struct z_erofs_decompressor erofs_decompressors[];
87-
88-
/* prototypes for specific algorithms */
89-
int z_erofs_load_lzma_config(struct super_block *sb,
90-
struct erofs_super_block *dsb, void *data, int size);
91-
int z_erofs_load_deflate_config(struct super_block *sb,
92-
struct erofs_super_block *dsb, void *data, int size);
93-
int z_erofs_load_zstd_config(struct super_block *sb,
94-
struct erofs_super_block *dsb, void *data, int size);
95-
int z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq,
96-
struct page **pagepool);
97-
int z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
98-
struct page **pagepool);
99-
int z_erofs_zstd_decompress(struct z_erofs_decompress_req *rq,
100-
struct page **pgpl);
98+
int __init z_erofs_init_decompressor(void);
99+
void z_erofs_exit_decompressor(void);
101100
#endif

fs/erofs/decompressor.c

Lines changed: 122 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/*
33
* Copyright (C) 2019 HUAWEI, Inc.
44
* https://www.huawei.com/
5+
* Copyright (C) 2024 Alibaba Cloud
56
*/
67
#include "compress.h"
78
#include <linux/lz4.h>
@@ -109,7 +110,6 @@ static int z_erofs_lz4_prepare_dstpages(struct z_erofs_lz4_decompress_ctx *ctx,
109110

110111
if (top) {
111112
victim = availables[--top];
112-
get_page(victim);
113113
} else {
114114
victim = __erofs_allocpage(pagepool, rq->gfp, true);
115115
if (!victim)
@@ -371,40 +371,113 @@ static int z_erofs_transform_plain(struct z_erofs_decompress_req *rq,
371371
return 0;
372372
}
373373

374-
const struct z_erofs_decompressor erofs_decompressors[] = {
375-
[Z_EROFS_COMPRESSION_SHIFTED] = {
374+
int z_erofs_stream_switch_bufs(struct z_erofs_stream_dctx *dctx, void **dst,
375+
void **src, struct page **pgpl)
376+
{
377+
struct z_erofs_decompress_req *rq = dctx->rq;
378+
struct super_block *sb = rq->sb;
379+
struct page **pgo, *tmppage;
380+
unsigned int j;
381+
382+
if (!dctx->avail_out) {
383+
if (++dctx->no >= dctx->outpages || !rq->outputsize) {
384+
erofs_err(sb, "insufficient space for decompressed data");
385+
return -EFSCORRUPTED;
386+
}
387+
388+
if (dctx->kout)
389+
kunmap_local(dctx->kout);
390+
dctx->avail_out = min(rq->outputsize, PAGE_SIZE - rq->pageofs_out);
391+
rq->outputsize -= dctx->avail_out;
392+
pgo = &rq->out[dctx->no];
393+
if (!*pgo && rq->fillgaps) { /* deduped */
394+
*pgo = erofs_allocpage(pgpl, rq->gfp);
395+
if (!*pgo) {
396+
dctx->kout = NULL;
397+
return -ENOMEM;
398+
}
399+
set_page_private(*pgo, Z_EROFS_SHORTLIVED_PAGE);
400+
}
401+
if (*pgo) {
402+
dctx->kout = kmap_local_page(*pgo);
403+
*dst = dctx->kout + rq->pageofs_out;
404+
} else {
405+
*dst = dctx->kout = NULL;
406+
}
407+
rq->pageofs_out = 0;
408+
}
409+
410+
if (dctx->inbuf_pos == dctx->inbuf_sz && rq->inputsize) {
411+
if (++dctx->ni >= dctx->inpages) {
412+
erofs_err(sb, "invalid compressed data");
413+
return -EFSCORRUPTED;
414+
}
415+
if (dctx->kout) /* unlike kmap(), take care of the orders */
416+
kunmap_local(dctx->kout);
417+
kunmap_local(dctx->kin);
418+
419+
dctx->inbuf_sz = min_t(u32, rq->inputsize, PAGE_SIZE);
420+
rq->inputsize -= dctx->inbuf_sz;
421+
dctx->kin = kmap_local_page(rq->in[dctx->ni]);
422+
*src = dctx->kin;
423+
dctx->bounced = false;
424+
if (dctx->kout) {
425+
j = (u8 *)*dst - dctx->kout;
426+
dctx->kout = kmap_local_page(rq->out[dctx->no]);
427+
*dst = dctx->kout + j;
428+
}
429+
dctx->inbuf_pos = 0;
430+
}
431+
432+
/*
433+
* Handle overlapping: Use the given bounce buffer if the input data is
434+
* under processing; Or utilize short-lived pages from the on-stack page
435+
* pool, where pages are shared among the same request. Note that only
436+
* a few inplace I/O pages need to be doubled.
437+
*/
438+
if (!dctx->bounced && rq->out[dctx->no] == rq->in[dctx->ni]) {
439+
memcpy(dctx->bounce, *src, dctx->inbuf_sz);
440+
*src = dctx->bounce;
441+
dctx->bounced = true;
442+
}
443+
444+
for (j = dctx->ni + 1; j < dctx->inpages; ++j) {
445+
if (rq->out[dctx->no] != rq->in[j])
446+
continue;
447+
tmppage = erofs_allocpage(pgpl, rq->gfp);
448+
if (!tmppage)
449+
return -ENOMEM;
450+
set_page_private(tmppage, Z_EROFS_SHORTLIVED_PAGE);
451+
copy_highpage(tmppage, rq->in[j]);
452+
rq->in[j] = tmppage;
453+
}
454+
return 0;
455+
}
456+
457+
const struct z_erofs_decompressor *z_erofs_decomp[] = {
458+
[Z_EROFS_COMPRESSION_SHIFTED] = &(const struct z_erofs_decompressor) {
376459
.decompress = z_erofs_transform_plain,
377460
.name = "shifted"
378461
},
379-
[Z_EROFS_COMPRESSION_INTERLACED] = {
462+
[Z_EROFS_COMPRESSION_INTERLACED] = &(const struct z_erofs_decompressor) {
380463
.decompress = z_erofs_transform_plain,
381464
.name = "interlaced"
382465
},
383-
[Z_EROFS_COMPRESSION_LZ4] = {
466+
[Z_EROFS_COMPRESSION_LZ4] = &(const struct z_erofs_decompressor) {
384467
.config = z_erofs_load_lz4_config,
385468
.decompress = z_erofs_lz4_decompress,
469+
.init = z_erofs_gbuf_init,
470+
.exit = z_erofs_gbuf_exit,
386471
.name = "lz4"
387472
},
388473
#ifdef CONFIG_EROFS_FS_ZIP_LZMA
389-
[Z_EROFS_COMPRESSION_LZMA] = {
390-
.config = z_erofs_load_lzma_config,
391-
.decompress = z_erofs_lzma_decompress,
392-
.name = "lzma"
393-
},
474+
[Z_EROFS_COMPRESSION_LZMA] = &z_erofs_lzma_decomp,
394475
#endif
395476
#ifdef CONFIG_EROFS_FS_ZIP_DEFLATE
396-
[Z_EROFS_COMPRESSION_DEFLATE] = {
397-
.config = z_erofs_load_deflate_config,
398-
.decompress = z_erofs_deflate_decompress,
399-
.name = "deflate"
400-
},
477+
[Z_EROFS_COMPRESSION_DEFLATE] = &z_erofs_deflate_decomp,
401478
#endif
402479
#ifdef CONFIG_EROFS_FS_ZIP_ZSTD
403-
[Z_EROFS_COMPRESSION_ZSTD] = {
404-
.config = z_erofs_load_zstd_config,
405-
.decompress = z_erofs_zstd_decompress,
406-
.name = "zstd"
407-
},
480+
[Z_EROFS_COMPRESSION_ZSTD] = &z_erofs_zstd_decomp,
408481
#endif
409482
};
410483

@@ -432,6 +505,7 @@ int z_erofs_parse_cfgs(struct super_block *sb, struct erofs_super_block *dsb)
432505
offset = EROFS_SUPER_OFFSET + sbi->sb_size;
433506
alg = 0;
434507
for (algs = sbi->available_compr_algs; algs; algs >>= 1, ++alg) {
508+
const struct z_erofs_decompressor *dec = z_erofs_decomp[alg];
435509
void *data;
436510

437511
if (!(algs & 1))
@@ -443,20 +517,42 @@ int z_erofs_parse_cfgs(struct super_block *sb, struct erofs_super_block *dsb)
443517
break;
444518
}
445519

446-
if (alg >= ARRAY_SIZE(erofs_decompressors) ||
447-
!erofs_decompressors[alg].config) {
520+
if (alg < Z_EROFS_COMPRESSION_MAX && dec && dec->config) {
521+
ret = dec->config(sb, dsb, data, size);
522+
} else {
448523
erofs_err(sb, "algorithm %d isn't enabled on this kernel",
449524
alg);
450525
ret = -EOPNOTSUPP;
451-
} else {
452-
ret = erofs_decompressors[alg].config(sb,
453-
dsb, data, size);
454526
}
455-
456527
kfree(data);
457528
if (ret)
458529
break;
459530
}
460531
erofs_put_metabuf(&buf);
461532
return ret;
462533
}
534+
535+
int __init z_erofs_init_decompressor(void)
536+
{
537+
int i, err;
538+
539+
for (i = 0; i < Z_EROFS_COMPRESSION_MAX; ++i) {
540+
err = z_erofs_decomp[i] ? z_erofs_decomp[i]->init() : 0;
541+
if (err) {
542+
while (--i)
543+
if (z_erofs_decomp[i])
544+
z_erofs_decomp[i]->exit();
545+
return err;
546+
}
547+
}
548+
return 0;
549+
}
550+
551+
void z_erofs_exit_decompressor(void)
552+
{
553+
int i;
554+
555+
for (i = 0; i < Z_EROFS_COMPRESSION_MAX; ++i)
556+
if (z_erofs_decomp[i])
557+
z_erofs_decomp[i]->exit();
558+
}

0 commit comments

Comments
 (0)