diff options
Diffstat (limited to 'fs/erofs')
-rw-r--r-- | fs/erofs/zdata.c | 34 |
1 files changed, 21 insertions, 13 deletions
diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c index 1cf377ed1452..d93ba0adcf9e 100644 --- a/fs/erofs/zdata.c +++ b/fs/erofs/zdata.c @@ -858,6 +858,7 @@ struct z_erofs_decompress_backend { struct page **compressed_pages; struct page **pagepool; + unsigned int onstack_used; }; static int z_erofs_parse_out_bvecs(struct z_erofs_decompress_backend *be) @@ -904,14 +905,9 @@ static int z_erofs_parse_in_bvecs(struct z_erofs_decompress_backend *be, { struct z_erofs_pcluster *pcl = be->pcl; unsigned int pclusterpages = z_erofs_pclusterpages(pcl); - struct page **compressed_pages; int i, err = 0; - /* XXX: will have a better approach in the following commits */ - compressed_pages = kmalloc_array(pclusterpages, sizeof(struct page *), - GFP_KERNEL | __GFP_NOFAIL); *overlapped = false; - for (i = 0; i < pclusterpages; ++i) { struct z_erofs_bvec *bvec = &pcl->compressed_bvecs[i]; struct page *page = bvec->page; @@ -922,7 +918,7 @@ static int z_erofs_parse_in_bvecs(struct z_erofs_decompress_backend *be, DBG_BUGON(1); continue; } - compressed_pages[i] = page; + be->compressed_pages[i] = page; if (z_erofs_is_inline_pcluster(pcl)) { if (!PageUptodate(page)) @@ -953,11 +949,8 @@ static int z_erofs_parse_in_bvecs(struct z_erofs_decompress_backend *be, } } - if (err) { - kfree(compressed_pages); + if (err) return err; - } - be->compressed_pages = compressed_pages; return 0; } @@ -976,15 +969,28 @@ static int z_erofs_decompress_pcluster(struct z_erofs_decompress_backend *be, mutex_lock(&pcl->lock); nr_pages = pcl->nr_pages; + /* allocate (de)compressed page arrays if cannot be kept on stack */ + be->decompressed_pages = NULL; + be->compressed_pages = NULL; + be->onstack_used = 0; if (nr_pages <= Z_EROFS_ONSTACK_PAGES) { be->decompressed_pages = be->onstack_pages; + be->onstack_used = nr_pages; memset(be->decompressed_pages, 0, sizeof(struct page *) * nr_pages); - } else { + } + + if (pclusterpages + be->onstack_used <= Z_EROFS_ONSTACK_PAGES) + be->compressed_pages = be->onstack_pages + be->onstack_used; + + if (!be->decompressed_pages) be->decompressed_pages = kvcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL | __GFP_NOFAIL); - } + if (!be->compressed_pages) + be->compressed_pages = + kvcalloc(pclusterpages, sizeof(struct page *), + GFP_KERNEL | __GFP_NOFAIL); err2 = z_erofs_parse_out_bvecs(be); if (err2) @@ -1041,7 +1047,9 @@ out: WRITE_ONCE(pcl->compressed_bvecs[i].page, NULL); } } - kfree(be->compressed_pages); + if (be->compressed_pages < be->onstack_pages || + be->compressed_pages >= be->onstack_pages + Z_EROFS_ONSTACK_PAGES) + kvfree(be->compressed_pages); for (i = 0; i < nr_pages; ++i) { page = be->decompressed_pages[i]; |