[PATCH 4/4] erofs: complete a missing case for inplace I/O

From: Gao Xiang
Date: Thu Oct 22 2020 - 10:58:11 EST


From: Gao Xiang <hsiangkao@xxxxxxxxxx>

Add a missing case which could cause unnecessary page allocation
but not directly use inplace I/O instead, which increases runtime
extra memory footprint.

The detail is, considering a file-backed page, the right half of
the page is chosen to be cached (e.g. the end page) and some of
its data doesn't exist in managed cache, so the pcluster will be
kept in the submission chain. (In other words, it cannot be
decompressed in advance, for example, due to the bypass chain).

Currently, the pcluster for this case is downgraded as NOINPLACE,
and stop the left half of the page from doing inplace I/O (so an
extra page allocation is needed then.)

Let's avoid such unnecessary downgrade instead.

Signed-off-by: Gao Xiang <hsiangkao@xxxxxxxxxx>
---
fs/erofs/zdata.c | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)

diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c
index edd7325570e1..ef12275f7fcc 100644
--- a/fs/erofs/zdata.c
+++ b/fs/erofs/zdata.c
@@ -160,7 +160,8 @@ static void preload_compressed_pages(struct z_erofs_collector *clt,
const unsigned int clusterpages = BIT(pcl->clusterbits);
struct page **pages = clt->compressedpages;
pgoff_t index = pcl->obj.index + (pages - pcl->compressed_pages);
- bool standalone = true;
+ bool io_cant_bypass = false;
+ bool updated = false;

if (clt->mode < COLLECT_PRIMARY_FOLLOWED)
return;
@@ -180,20 +181,31 @@ static void preload_compressed_pages(struct z_erofs_collector *clt,
} else if (type == DELAYEDALLOC) {
t = tagptr_init(compressed_page_t, PAGE_UNALLOCATED);
} else { /* DONTALLOC */
- if (standalone)
+ /* update to first inplace I/O page */
+ if (!updated) {
clt->compressedpages = pages;
- standalone = false;
+ updated = true;
+ }
+ io_cant_bypass = true;
continue;
}

- if (!cmpxchg_relaxed(pages, NULL, tagptr_cast_ptr(t)))
+ if (!cmpxchg_relaxed(pages, NULL, tagptr_cast_ptr(t))) {
+ if (type == DELAYEDALLOC)
+ io_cant_bypass = true;
continue;
+ }

if (page)
put_page(page);
}

- if (standalone) /* downgrade to PRIMARY_FOLLOWED_NOINPLACE */
+ /*
+ * for COLLECT_PRIMARY_FOLLOWED pcluster, if all managed pages have
+ * been found (which means it can be handled without submittng I/O)
+ * it's unsafe to do inplace I/O. let's downgrade to NOINPLACE instead.
+ */
+ if (!io_cant_bypass)
clt->mode = COLLECT_PRIMARY_FOLLOWED_NOINPLACE;
}

--
2.24.0