erofs: introduce struct z_erofs_decompress_backend

Let's introduce struct z_erofs_decompress_backend in order to pass
on the decompression backend context between helper functions more
easier and avoid too many arguments.

Acked-by: Chao Yu <chao@kernel.org>
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20220715154203.48093-13-hsiangkao@linux.alibaba.com
This commit is contained in:
Gao Xiang 2022-07-15 23:41:59 +08:00
parent e73681877d
commit 4f05687fd7
2 changed files with 76 additions and 67 deletions

View File

@ -847,9 +847,22 @@ static bool z_erofs_page_is_invalidated(struct page *page)
return !page->mapping && !z_erofs_is_shortlived_page(page); return !page->mapping && !z_erofs_is_shortlived_page(page);
} }
static int z_erofs_parse_out_bvecs(struct z_erofs_pcluster *pcl, struct z_erofs_decompress_backend {
struct page **pages, struct page **pagepool) struct page *onstack_pages[Z_EROFS_ONSTACK_PAGES];
struct super_block *sb;
struct z_erofs_pcluster *pcl;
/* pages with the longest decompressed length for deduplication */
struct page **decompressed_pages;
/* pages to keep the compressed data */
struct page **compressed_pages;
struct page **pagepool;
};
static int z_erofs_parse_out_bvecs(struct z_erofs_decompress_backend *be)
{ {
struct z_erofs_pcluster *pcl = be->pcl;
struct z_erofs_bvec_iter biter; struct z_erofs_bvec_iter biter;
struct page *old_bvpage; struct page *old_bvpage;
int i, err = 0; int i, err = 0;
@ -857,39 +870,39 @@ static int z_erofs_parse_out_bvecs(struct z_erofs_pcluster *pcl,
z_erofs_bvec_iter_begin(&biter, &pcl->bvset, Z_EROFS_INLINE_BVECS, 0); z_erofs_bvec_iter_begin(&biter, &pcl->bvset, Z_EROFS_INLINE_BVECS, 0);
for (i = 0; i < pcl->vcnt; ++i) { for (i = 0; i < pcl->vcnt; ++i) {
struct z_erofs_bvec bvec; struct z_erofs_bvec bvec;
unsigned int pagenr; unsigned int pgnr;
z_erofs_bvec_dequeue(&biter, &bvec, &old_bvpage); z_erofs_bvec_dequeue(&biter, &bvec, &old_bvpage);
if (old_bvpage) if (old_bvpage)
z_erofs_put_shortlivedpage(pagepool, old_bvpage); z_erofs_put_shortlivedpage(be->pagepool, old_bvpage);
pagenr = (bvec.offset + pcl->pageofs_out) >> PAGE_SHIFT; pgnr = (bvec.offset + pcl->pageofs_out) >> PAGE_SHIFT;
DBG_BUGON(pagenr >= pcl->nr_pages); DBG_BUGON(pgnr >= pcl->nr_pages);
DBG_BUGON(z_erofs_page_is_invalidated(bvec.page)); DBG_BUGON(z_erofs_page_is_invalidated(bvec.page));
/* /*
* currently EROFS doesn't support multiref(dedup), * currently EROFS doesn't support multiref(dedup),
* so here erroring out one multiref page. * so here erroring out one multiref page.
*/ */
if (pages[pagenr]) { if (be->decompressed_pages[pgnr]) {
DBG_BUGON(1); DBG_BUGON(1);
z_erofs_page_mark_eio(pages[pagenr]); z_erofs_page_mark_eio(be->decompressed_pages[pgnr]);
z_erofs_onlinepage_endio(pages[pagenr]); z_erofs_onlinepage_endio(be->decompressed_pages[pgnr]);
err = -EFSCORRUPTED; err = -EFSCORRUPTED;
} }
pages[pagenr] = bvec.page; be->decompressed_pages[pgnr] = bvec.page;
} }
old_bvpage = z_erofs_bvec_iter_end(&biter); old_bvpage = z_erofs_bvec_iter_end(&biter);
if (old_bvpage) if (old_bvpage)
z_erofs_put_shortlivedpage(pagepool, old_bvpage); z_erofs_put_shortlivedpage(be->pagepool, old_bvpage);
return err; return err;
} }
static struct page **z_erofs_parse_in_bvecs(struct erofs_sb_info *sbi, static int z_erofs_parse_in_bvecs(struct z_erofs_decompress_backend *be,
struct z_erofs_pcluster *pcl, struct page **pages, bool *overlapped)
struct page **pagepool, bool *overlapped)
{ {
struct z_erofs_pcluster *pcl = be->pcl;
unsigned int pclusterpages = z_erofs_pclusterpages(pcl); unsigned int pclusterpages = z_erofs_pclusterpages(pcl);
struct page **compressed_pages; struct page **compressed_pages;
int i, err = 0; int i, err = 0;
@ -919,7 +932,7 @@ static struct page **z_erofs_parse_in_bvecs(struct erofs_sb_info *sbi,
DBG_BUGON(z_erofs_page_is_invalidated(page)); DBG_BUGON(z_erofs_page_is_invalidated(page));
if (!z_erofs_is_shortlived_page(page)) { if (!z_erofs_is_shortlived_page(page)) {
if (erofs_page_is_managed(sbi, page)) { if (erofs_page_is_managed(EROFS_SB(be->sb), page)) {
if (!PageUptodate(page)) if (!PageUptodate(page))
err = -EIO; err = -EIO;
continue; continue;
@ -927,60 +940,58 @@ static struct page **z_erofs_parse_in_bvecs(struct erofs_sb_info *sbi,
pgnr = (bvec->offset + pcl->pageofs_out) >> PAGE_SHIFT; pgnr = (bvec->offset + pcl->pageofs_out) >> PAGE_SHIFT;
DBG_BUGON(pgnr >= pcl->nr_pages); DBG_BUGON(pgnr >= pcl->nr_pages);
if (pages[pgnr]) { if (be->decompressed_pages[pgnr]) {
DBG_BUGON(1); DBG_BUGON(1);
z_erofs_page_mark_eio(pages[pgnr]); z_erofs_page_mark_eio(
z_erofs_onlinepage_endio(pages[pgnr]); be->decompressed_pages[pgnr]);
z_erofs_onlinepage_endio(
be->decompressed_pages[pgnr]);
err = -EFSCORRUPTED; err = -EFSCORRUPTED;
} }
pages[pgnr] = page; be->decompressed_pages[pgnr] = page;
*overlapped = true; *overlapped = true;
} }
} }
if (err) { if (err) {
kfree(compressed_pages); kfree(compressed_pages);
return ERR_PTR(err); return err;
} }
return compressed_pages; be->compressed_pages = compressed_pages;
return 0;
} }
static int z_erofs_decompress_pcluster(struct super_block *sb, static int z_erofs_decompress_pcluster(struct z_erofs_decompress_backend *be,
struct z_erofs_pcluster *pcl, int err)
struct page **pagepool, int err)
{ {
struct erofs_sb_info *const sbi = EROFS_SB(sb); struct erofs_sb_info *const sbi = EROFS_SB(be->sb);
struct z_erofs_pcluster *pcl = be->pcl;
unsigned int pclusterpages = z_erofs_pclusterpages(pcl); unsigned int pclusterpages = z_erofs_pclusterpages(pcl);
unsigned int i, inputsize, outputsize, llen, nr_pages; unsigned int i, inputsize, outputsize, llen, nr_pages;
struct page *pages_onstack[Z_EROFS_VMAP_ONSTACK_PAGES]; struct page *page;
struct page **pages, **compressed_pages, *page;
int err2; int err2;
bool overlapped, partial; bool overlapped, partial;
might_sleep();
DBG_BUGON(!READ_ONCE(pcl->nr_pages)); DBG_BUGON(!READ_ONCE(pcl->nr_pages));
mutex_lock(&pcl->lock); mutex_lock(&pcl->lock);
nr_pages = pcl->nr_pages; nr_pages = pcl->nr_pages;
if (nr_pages <= Z_EROFS_VMAP_ONSTACK_PAGES) if (nr_pages <= Z_EROFS_ONSTACK_PAGES) {
pages = pages_onstack; be->decompressed_pages = be->onstack_pages;
else memset(be->decompressed_pages, 0,
pages = kvmalloc_array(nr_pages, sizeof(struct page *), sizeof(struct page *) * nr_pages);
GFP_KERNEL | __GFP_NOFAIL); } else {
be->decompressed_pages =
kvcalloc(nr_pages, sizeof(struct page *),
GFP_KERNEL | __GFP_NOFAIL);
}
for (i = 0; i < nr_pages; ++i) err2 = z_erofs_parse_out_bvecs(be);
pages[i] = NULL; if (err2)
err = err2;
err2 = z_erofs_parse_out_bvecs(pcl, pages, pagepool); err2 = z_erofs_parse_in_bvecs(be, &overlapped);
if (err2) if (err2)
err = err2; err = err2;
compressed_pages = z_erofs_parse_in_bvecs(sbi, pcl, pages,
pagepool, &overlapped);
if (IS_ERR(compressed_pages)) {
err = PTR_ERR(compressed_pages);
compressed_pages = NULL;
}
if (err) if (err)
goto out; goto out;
@ -1000,9 +1011,9 @@ static int z_erofs_decompress_pcluster(struct super_block *sb,
inputsize = pclusterpages * PAGE_SIZE; inputsize = pclusterpages * PAGE_SIZE;
err = z_erofs_decompress(&(struct z_erofs_decompress_req) { err = z_erofs_decompress(&(struct z_erofs_decompress_req) {
.sb = sb, .sb = be->sb,
.in = compressed_pages, .in = be->compressed_pages,
.out = pages, .out = be->decompressed_pages,
.pageofs_in = pcl->pageofs_in, .pageofs_in = pcl->pageofs_in,
.pageofs_out = pcl->pageofs_out, .pageofs_out = pcl->pageofs_out,
.inputsize = inputsize, .inputsize = inputsize,
@ -1010,7 +1021,7 @@ static int z_erofs_decompress_pcluster(struct super_block *sb,
.alg = pcl->algorithmformat, .alg = pcl->algorithmformat,
.inplace_io = overlapped, .inplace_io = overlapped,
.partial_decoding = partial .partial_decoding = partial
}, pagepool); }, be->pagepool);
out: out:
/* must handle all compressed pages before actual file pages */ /* must handle all compressed pages before actual file pages */
@ -1026,29 +1037,29 @@ out:
continue; continue;
/* recycle all individual short-lived pages */ /* recycle all individual short-lived pages */
(void)z_erofs_put_shortlivedpage(pagepool, page); (void)z_erofs_put_shortlivedpage(be->pagepool, page);
WRITE_ONCE(pcl->compressed_bvecs[i].page, NULL); WRITE_ONCE(pcl->compressed_bvecs[i].page, NULL);
} }
} }
kfree(compressed_pages); kfree(be->compressed_pages);
for (i = 0; i < nr_pages; ++i) { for (i = 0; i < nr_pages; ++i) {
page = pages[i]; page = be->decompressed_pages[i];
if (!page) if (!page)
continue; continue;
DBG_BUGON(z_erofs_page_is_invalidated(page)); DBG_BUGON(z_erofs_page_is_invalidated(page));
/* recycle all individual short-lived pages */ /* recycle all individual short-lived pages */
if (z_erofs_put_shortlivedpage(pagepool, page)) if (z_erofs_put_shortlivedpage(be->pagepool, page))
continue; continue;
if (err) if (err)
z_erofs_page_mark_eio(page); z_erofs_page_mark_eio(page);
z_erofs_onlinepage_endio(page); z_erofs_onlinepage_endio(page);
} }
if (pages != pages_onstack) if (be->decompressed_pages != be->onstack_pages)
kvfree(pages); kvfree(be->decompressed_pages);
pcl->nr_pages = 0; pcl->nr_pages = 0;
pcl->bvset.nextpage = NULL; pcl->bvset.nextpage = NULL;
@ -1063,23 +1074,23 @@ out:
static void z_erofs_decompress_queue(const struct z_erofs_decompressqueue *io, static void z_erofs_decompress_queue(const struct z_erofs_decompressqueue *io,
struct page **pagepool) struct page **pagepool)
{ {
struct z_erofs_decompress_backend be = {
.sb = io->sb,
.pagepool = pagepool,
};
z_erofs_next_pcluster_t owned = io->head; z_erofs_next_pcluster_t owned = io->head;
while (owned != Z_EROFS_PCLUSTER_TAIL_CLOSED) { while (owned != Z_EROFS_PCLUSTER_TAIL_CLOSED) {
struct z_erofs_pcluster *pcl; /* impossible that 'owned' equals Z_EROFS_WORK_TPTR_TAIL */
/* no possible that 'owned' equals Z_EROFS_WORK_TPTR_TAIL */
DBG_BUGON(owned == Z_EROFS_PCLUSTER_TAIL); DBG_BUGON(owned == Z_EROFS_PCLUSTER_TAIL);
/* impossible that 'owned' equals Z_EROFS_PCLUSTER_NIL */
/* no possible that 'owned' equals NULL */
DBG_BUGON(owned == Z_EROFS_PCLUSTER_NIL); DBG_BUGON(owned == Z_EROFS_PCLUSTER_NIL);
pcl = container_of(owned, struct z_erofs_pcluster, next); be.pcl = container_of(owned, struct z_erofs_pcluster, next);
owned = READ_ONCE(pcl->next); owned = READ_ONCE(be.pcl->next);
z_erofs_decompress_pcluster(io->sb, pcl, pagepool, z_erofs_decompress_pcluster(&be, io->eio ? -EIO : 0);
io->eio ? -EIO : 0); erofs_workgroup_put(&be.pcl->obj);
erofs_workgroup_put(&pcl->obj);
} }
} }
@ -1105,7 +1116,6 @@ static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io,
if (sync) { if (sync) {
if (!atomic_add_return(bios, &io->pending_bios)) if (!atomic_add_return(bios, &io->pending_bios))
complete(&io->u.done); complete(&io->u.done);
return; return;
} }

View File

@ -173,7 +173,6 @@ static inline void z_erofs_onlinepage_endio(struct page *page)
} }
} }
#define Z_EROFS_VMAP_ONSTACK_PAGES \ #define Z_EROFS_ONSTACK_PAGES 32
min_t(unsigned int, THREAD_SIZE / 8 / sizeof(struct page *), 96U)
#endif #endif