[PATCH] ksm: delay the check of splitting compound pages

From: yang.yang29
Date: Tue Nov 14 2023 - 07:37:30 EST


From: xu xin <xu.xin16@xxxxxxxxxx>

Background
==========
When trying to merge two pages, it may fail because the two pages
belongs to the same compound page and split_huge_page fails due to
the incorrect reference to the page. To solve the problem, the commit
77da2ba0648a4 ("mm/ksm: fix interaction with THP") tries to split the
compound page after try_to_merge_two_pages() fails and put_page in
that case. However it is too early to calculate of the variable 'split' which
indicates whether the two pages belongs to the same compound page.

What to do
==========
If try_to_merge_two_pages() succeeds, there is no need to check whether
to splitting compound pages. So we delay the check of splitting compound
pages until try_to_merge_two_pages() fails, which can improve the
processing efficiency of cmp_and_merge_page() a little.

Signed-off-by: xu xin <xu.xin16@xxxxxxxxxx>
Reviewed-by: Yang Yang <yang.yang29@xxxxxxxxxx>
---
mm/ksm.c | 36 ++++++++++++++++++++----------------
1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/mm/ksm.c b/mm/ksm.c
index 7efcc68ccc6e..c952fe5d9e43 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -2229,24 +2229,10 @@ static void cmp_and_merge_page(struct page *page, struct ksm_rmap_item *rmap_ite
tree_rmap_item =
unstable_tree_search_insert(rmap_item, page, &tree_page);
if (tree_rmap_item) {
- bool split;
-
kpage = try_to_merge_two_pages(rmap_item, page,
tree_rmap_item, tree_page);
- /*
- * If both pages we tried to merge belong to the same compound
- * page, then we actually ended up increasing the reference
- * count of the same compound page twice, and split_huge_page
- * failed.
- * Here we set a flag if that happened, and we use it later to
- * try split_huge_page again. Since we call put_page right
- * afterwards, the reference count will be correct and
- * split_huge_page should succeed.
- */
- split = PageTransCompound(page)
- && compound_head(page) == compound_head(tree_page);
- put_page(tree_page);
if (kpage) {
+ put_page(tree_page);
/*
* The pages were successfully merged: insert new
* node in the stable tree and add both rmap_items.
@@ -2271,7 +2257,25 @@ static void cmp_and_merge_page(struct page *page, struct ksm_rmap_item *rmap_ite
break_cow(tree_rmap_item);
break_cow(rmap_item);
}
- } else if (split) {
+ } else {
+ bool split;
+ /*
+ * If both pages we tried to merge belong to the same compound
+ * page, then we actually ended up increasing the reference
+ * count of the same compound page twice, and split_huge_page
+ * failed.
+ * Here we set a flag if that happened, and we use it later to
+ * try split_huge_page again. Since we call put_page right
+ * afterwards, the reference count will be correct and
+ * split_huge_page should succeed.
+ */
+
+ split = PageTransCompound(page)
+ && compound_head(page) == compound_head(tree_page);
+ put_page(tree_page);
+
+ if (!split)
+ return;
/*
* We are here if we tried to merge two pages and
* failed because they both belonged to the same
--
2.15.2