Commit ed722fbc authored by Gao Xiang's avatar Gao Xiang

erofs: switch compressed_pages[] to bufvec

Convert compressed_pages[] to bufvec in order to avoid using
page->private to keep onlinepage_index (decompressed offset)
for inplace I/O pages.

In the future, we only rely on folio->private to keep a countdown
to unlock folios and set folio_uptodate.
Acked-by: default avatarChao Yu <chao@kernel.org>
Signed-off-by: default avatarGao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20220715154203.48093-8-hsiangkao@linux.alibaba.com
parent 67139e36
...@@ -134,7 +134,7 @@ static int z_erofs_create_pcluster_pool(void) ...@@ -134,7 +134,7 @@ static int z_erofs_create_pcluster_pool(void)
for (pcs = pcluster_pool; for (pcs = pcluster_pool;
pcs < pcluster_pool + ARRAY_SIZE(pcluster_pool); ++pcs) { pcs < pcluster_pool + ARRAY_SIZE(pcluster_pool); ++pcs) {
size = struct_size(a, compressed_pages, pcs->maxpages); size = struct_size(a, compressed_bvecs, pcs->maxpages);
sprintf(pcs->name, "erofs_pcluster-%u", pcs->maxpages); sprintf(pcs->name, "erofs_pcluster-%u", pcs->maxpages);
pcs->slab = kmem_cache_create(pcs->name, size, 0, pcs->slab = kmem_cache_create(pcs->name, size, 0,
...@@ -287,16 +287,16 @@ struct z_erofs_decompress_frontend { ...@@ -287,16 +287,16 @@ struct z_erofs_decompress_frontend {
struct page *candidate_bvpage; struct page *candidate_bvpage;
struct z_erofs_pcluster *pcl, *tailpcl; struct z_erofs_pcluster *pcl, *tailpcl;
/* a pointer used to pick up inplace I/O pages */
struct page **icpage_ptr;
z_erofs_next_pcluster_t owned_head; z_erofs_next_pcluster_t owned_head;
enum z_erofs_collectmode mode; enum z_erofs_collectmode mode;
bool readahead; bool readahead;
/* used for applying cache strategy on the fly */ /* used for applying cache strategy on the fly */
bool backmost; bool backmost;
erofs_off_t headoffset; erofs_off_t headoffset;
/* a pointer used to pick up inplace I/O pages */
unsigned int icur;
}; };
#define DECOMPRESS_FRONTEND_INIT(__i) { \ #define DECOMPRESS_FRONTEND_INIT(__i) { \
...@@ -319,24 +319,21 @@ static void z_erofs_bind_cache(struct z_erofs_decompress_frontend *fe, ...@@ -319,24 +319,21 @@ static void z_erofs_bind_cache(struct z_erofs_decompress_frontend *fe,
*/ */
gfp_t gfp = (mapping_gfp_mask(mc) & ~__GFP_DIRECT_RECLAIM) | gfp_t gfp = (mapping_gfp_mask(mc) & ~__GFP_DIRECT_RECLAIM) |
__GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN; __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN;
struct page **pages; unsigned int i;
pgoff_t index;
if (fe->mode < COLLECT_PRIMARY_FOLLOWED) if (fe->mode < COLLECT_PRIMARY_FOLLOWED)
return; return;
pages = pcl->compressed_pages; for (i = 0; i < pcl->pclusterpages; ++i) {
index = pcl->obj.index;
for (; index < pcl->obj.index + pcl->pclusterpages; ++index, ++pages) {
struct page *page; struct page *page;
compressed_page_t t; compressed_page_t t;
struct page *newpage = NULL; struct page *newpage = NULL;
/* the compressed page was loaded before */ /* the compressed page was loaded before */
if (READ_ONCE(*pages)) if (READ_ONCE(pcl->compressed_bvecs[i].page))
continue; continue;
page = find_get_page(mc, index); page = find_get_page(mc, pcl->obj.index + i);
if (page) { if (page) {
t = tag_compressed_page_justfound(page); t = tag_compressed_page_justfound(page);
...@@ -357,7 +354,8 @@ static void z_erofs_bind_cache(struct z_erofs_decompress_frontend *fe, ...@@ -357,7 +354,8 @@ static void z_erofs_bind_cache(struct z_erofs_decompress_frontend *fe,
} }
} }
if (!cmpxchg_relaxed(pages, NULL, tagptr_cast_ptr(t))) if (!cmpxchg_relaxed(&pcl->compressed_bvecs[i].page, NULL,
tagptr_cast_ptr(t)))
continue; continue;
if (page) if (page)
...@@ -388,7 +386,7 @@ int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi, ...@@ -388,7 +386,7 @@ int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi,
* therefore no need to worry about available decompression users. * therefore no need to worry about available decompression users.
*/ */
for (i = 0; i < pcl->pclusterpages; ++i) { for (i = 0; i < pcl->pclusterpages; ++i) {
struct page *page = pcl->compressed_pages[i]; struct page *page = pcl->compressed_bvecs[i].page;
if (!page) if (!page)
continue; continue;
...@@ -401,7 +399,7 @@ int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi, ...@@ -401,7 +399,7 @@ int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi,
continue; continue;
/* barrier is implied in the following 'unlock_page' */ /* barrier is implied in the following 'unlock_page' */
WRITE_ONCE(pcl->compressed_pages[i], NULL); WRITE_ONCE(pcl->compressed_bvecs[i].page, NULL);
detach_page_private(page); detach_page_private(page);
unlock_page(page); unlock_page(page);
} }
...@@ -411,36 +409,39 @@ int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi, ...@@ -411,36 +409,39 @@ int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi,
int erofs_try_to_free_cached_page(struct page *page) int erofs_try_to_free_cached_page(struct page *page)
{ {
struct z_erofs_pcluster *const pcl = (void *)page_private(page); struct z_erofs_pcluster *const pcl = (void *)page_private(page);
int ret = 0; /* 0 - busy */ int ret, i;
if (erofs_workgroup_try_to_freeze(&pcl->obj, 1)) { if (!erofs_workgroup_try_to_freeze(&pcl->obj, 1))
unsigned int i; return 0;
DBG_BUGON(z_erofs_is_inline_pcluster(pcl)); ret = 0;
for (i = 0; i < pcl->pclusterpages; ++i) { DBG_BUGON(z_erofs_is_inline_pcluster(pcl));
if (pcl->compressed_pages[i] == page) { for (i = 0; i < pcl->pclusterpages; ++i) {
WRITE_ONCE(pcl->compressed_pages[i], NULL); if (pcl->compressed_bvecs[i].page == page) {
ret = 1; WRITE_ONCE(pcl->compressed_bvecs[i].page, NULL);
break; ret = 1;
} break;
} }
erofs_workgroup_unfreeze(&pcl->obj, 1);
if (ret)
detach_page_private(page);
} }
erofs_workgroup_unfreeze(&pcl->obj, 1);
if (ret)
detach_page_private(page);
return ret; return ret;
} }
/* page_type must be Z_EROFS_PAGE_TYPE_EXCLUSIVE */ /* page_type must be Z_EROFS_PAGE_TYPE_EXCLUSIVE */
static bool z_erofs_try_inplace_io(struct z_erofs_decompress_frontend *fe, static bool z_erofs_try_inplace_io(struct z_erofs_decompress_frontend *fe,
struct page *page) struct z_erofs_bvec *bvec)
{ {
struct z_erofs_pcluster *const pcl = fe->pcl; struct z_erofs_pcluster *const pcl = fe->pcl;
while (fe->icpage_ptr > pcl->compressed_pages) while (fe->icur > 0) {
if (!cmpxchg(--fe->icpage_ptr, NULL, page)) if (!cmpxchg(&pcl->compressed_bvecs[--fe->icur].page,
NULL, bvec->page)) {
pcl->compressed_bvecs[fe->icur] = *bvec;
return true; return true;
}
}
return false; return false;
} }
...@@ -454,7 +455,7 @@ static int z_erofs_attach_page(struct z_erofs_decompress_frontend *fe, ...@@ -454,7 +455,7 @@ static int z_erofs_attach_page(struct z_erofs_decompress_frontend *fe,
if (fe->mode >= COLLECT_PRIMARY && if (fe->mode >= COLLECT_PRIMARY &&
type == Z_EROFS_PAGE_TYPE_EXCLUSIVE) { type == Z_EROFS_PAGE_TYPE_EXCLUSIVE) {
/* give priority for inplaceio to use file pages first */ /* give priority for inplaceio to use file pages first */
if (z_erofs_try_inplace_io(fe, bvec->page)) if (z_erofs_try_inplace_io(fe, bvec))
return 0; return 0;
/* otherwise, check if it can be used as a bvpage */ /* otherwise, check if it can be used as a bvpage */
if (fe->mode >= COLLECT_PRIMARY_FOLLOWED && if (fe->mode >= COLLECT_PRIMARY_FOLLOWED &&
...@@ -648,8 +649,7 @@ static int z_erofs_collector_begin(struct z_erofs_decompress_frontend *fe) ...@@ -648,8 +649,7 @@ static int z_erofs_collector_begin(struct z_erofs_decompress_frontend *fe)
z_erofs_bvec_iter_begin(&fe->biter, &fe->pcl->bvset, z_erofs_bvec_iter_begin(&fe->biter, &fe->pcl->bvset,
Z_EROFS_INLINE_BVECS, fe->pcl->vcnt); Z_EROFS_INLINE_BVECS, fe->pcl->vcnt);
/* since file-backed online pages are traversed in reverse order */ /* since file-backed online pages are traversed in reverse order */
fe->icpage_ptr = fe->pcl->compressed_pages + fe->icur = z_erofs_pclusterpages(fe->pcl);
z_erofs_pclusterpages(fe->pcl);
return 0; return 0;
} }
...@@ -769,7 +769,8 @@ static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe, ...@@ -769,7 +769,8 @@ static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe,
goto err_out; goto err_out;
} }
get_page(fe->map.buf.page); get_page(fe->map.buf.page);
WRITE_ONCE(fe->pcl->compressed_pages[0], fe->map.buf.page); WRITE_ONCE(fe->pcl->compressed_bvecs[0].page,
fe->map.buf.page);
fe->mode = COLLECT_PRIMARY_FOLLOWED_NOINPLACE; fe->mode = COLLECT_PRIMARY_FOLLOWED_NOINPLACE;
} else { } else {
/* bind cache first when cached decompression is preferred */ /* bind cache first when cached decompression is preferred */
...@@ -927,8 +928,9 @@ static struct page **z_erofs_parse_in_bvecs(struct erofs_sb_info *sbi, ...@@ -927,8 +928,9 @@ static struct page **z_erofs_parse_in_bvecs(struct erofs_sb_info *sbi,
*overlapped = false; *overlapped = false;
for (i = 0; i < pclusterpages; ++i) { for (i = 0; i < pclusterpages; ++i) {
unsigned int pagenr; struct z_erofs_bvec *bvec = &pcl->compressed_bvecs[i];
struct page *page = pcl->compressed_pages[i]; struct page *page = bvec->page;
unsigned int pgnr;
/* compressed pages ought to be present before decompressing */ /* compressed pages ought to be present before decompressing */
if (!page) { if (!page) {
...@@ -951,21 +953,15 @@ static struct page **z_erofs_parse_in_bvecs(struct erofs_sb_info *sbi, ...@@ -951,21 +953,15 @@ static struct page **z_erofs_parse_in_bvecs(struct erofs_sb_info *sbi,
continue; continue;
} }
/* pgnr = (bvec->offset + pcl->pageofs_out) >> PAGE_SHIFT;
* only if non-head page can be selected DBG_BUGON(pgnr >= pcl->nr_pages);
* for inplace decompression if (pages[pgnr]) {
*/
pagenr = z_erofs_onlinepage_index(page);
DBG_BUGON(pagenr >= pcl->nr_pages);
if (pages[pagenr]) {
DBG_BUGON(1); DBG_BUGON(1);
SetPageError(pages[pagenr]); SetPageError(pages[pgnr]);
z_erofs_onlinepage_endio(pages[pagenr]); z_erofs_onlinepage_endio(pages[pgnr]);
err = -EFSCORRUPTED; err = -EFSCORRUPTED;
} }
pages[pagenr] = page; pages[pgnr] = page;
*overlapped = true; *overlapped = true;
} }
...@@ -1067,19 +1063,19 @@ static int z_erofs_decompress_pcluster(struct super_block *sb, ...@@ -1067,19 +1063,19 @@ static int z_erofs_decompress_pcluster(struct super_block *sb,
out: out:
/* must handle all compressed pages before actual file pages */ /* must handle all compressed pages before actual file pages */
if (z_erofs_is_inline_pcluster(pcl)) { if (z_erofs_is_inline_pcluster(pcl)) {
page = pcl->compressed_pages[0]; page = pcl->compressed_bvecs[0].page;
WRITE_ONCE(pcl->compressed_pages[0], NULL); WRITE_ONCE(pcl->compressed_bvecs[0].page, NULL);
put_page(page); put_page(page);
} else { } else {
for (i = 0; i < pclusterpages; ++i) { for (i = 0; i < pclusterpages; ++i) {
page = pcl->compressed_pages[i]; page = pcl->compressed_bvecs[i].page;
if (erofs_page_is_managed(sbi, page)) if (erofs_page_is_managed(sbi, page))
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(pagepool, page);
WRITE_ONCE(pcl->compressed_pages[i], NULL); WRITE_ONCE(pcl->compressed_bvecs[i].page, NULL);
} }
} }
kfree(compressed_pages); kfree(compressed_pages);
...@@ -1193,7 +1189,7 @@ static struct page *pickup_page_for_submission(struct z_erofs_pcluster *pcl, ...@@ -1193,7 +1189,7 @@ static struct page *pickup_page_for_submission(struct z_erofs_pcluster *pcl,
int justfound; int justfound;
repeat: repeat:
page = READ_ONCE(pcl->compressed_pages[nr]); page = READ_ONCE(pcl->compressed_bvecs[nr].page);
oldpage = page; oldpage = page;
if (!page) if (!page)
...@@ -1209,7 +1205,7 @@ static struct page *pickup_page_for_submission(struct z_erofs_pcluster *pcl, ...@@ -1209,7 +1205,7 @@ static struct page *pickup_page_for_submission(struct z_erofs_pcluster *pcl,
* otherwise, it will go inplace I/O path instead. * otherwise, it will go inplace I/O path instead.
*/ */
if (page->private == Z_EROFS_PREALLOCATED_PAGE) { if (page->private == Z_EROFS_PREALLOCATED_PAGE) {
WRITE_ONCE(pcl->compressed_pages[nr], page); WRITE_ONCE(pcl->compressed_bvecs[nr].page, page);
set_page_private(page, 0); set_page_private(page, 0);
tocache = true; tocache = true;
goto out_tocache; goto out_tocache;
...@@ -1235,14 +1231,14 @@ static struct page *pickup_page_for_submission(struct z_erofs_pcluster *pcl, ...@@ -1235,14 +1231,14 @@ static struct page *pickup_page_for_submission(struct z_erofs_pcluster *pcl,
/* the page is still in manage cache */ /* the page is still in manage cache */
if (page->mapping == mc) { if (page->mapping == mc) {
WRITE_ONCE(pcl->compressed_pages[nr], page); WRITE_ONCE(pcl->compressed_bvecs[nr].page, page);
ClearPageError(page); ClearPageError(page);
if (!PagePrivate(page)) { if (!PagePrivate(page)) {
/* /*
* impossible to be !PagePrivate(page) for * impossible to be !PagePrivate(page) for
* the current restriction as well if * the current restriction as well if
* the page is already in compressed_pages[]. * the page is already in compressed_bvecs[].
*/ */
DBG_BUGON(!justfound); DBG_BUGON(!justfound);
...@@ -1271,7 +1267,8 @@ static struct page *pickup_page_for_submission(struct z_erofs_pcluster *pcl, ...@@ -1271,7 +1267,8 @@ static struct page *pickup_page_for_submission(struct z_erofs_pcluster *pcl,
put_page(page); put_page(page);
out_allocpage: out_allocpage:
page = erofs_allocpage(pagepool, gfp | __GFP_NOFAIL); page = erofs_allocpage(pagepool, gfp | __GFP_NOFAIL);
if (oldpage != cmpxchg(&pcl->compressed_pages[nr], oldpage, page)) { if (oldpage != cmpxchg(&pcl->compressed_bvecs[nr].page,
oldpage, page)) {
erofs_pagepool_add(pagepool, page); erofs_pagepool_add(pagepool, page);
cond_resched(); cond_resched();
goto repeat; goto repeat;
......
...@@ -87,8 +87,8 @@ struct z_erofs_pcluster { ...@@ -87,8 +87,8 @@ struct z_erofs_pcluster {
/* I: compression algorithm format */ /* I: compression algorithm format */
unsigned char algorithmformat; unsigned char algorithmformat;
/* A: compressed pages (can be cached or inplaced pages) */ /* A: compressed bvecs (can be cached or inplaced pages) */
struct page *compressed_pages[]; struct z_erofs_bvec compressed_bvecs[];
}; };
/* let's avoid the valid 32-bit kernel addresses */ /* let's avoid the valid 32-bit kernel addresses */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment