Skip to content

Commit a0b856b

Browse files
cmzxoakpm00
authored andcommitted
mm/ksm: optimize the chain()/chain_prune() interfaces
Now the implementation of stable_node_dup() causes chain()/chain_prune() interfaces and usages are overcomplicated. Why? stable_node_dup() only find and return a candidate stable_node for sharing, so the users have to recheck using stable_node_dup_any() if any non-candidate stable_node exist. And try to ksm_get_folio() from it again. Actually, stable_node_dup() can just return a best stable_node as it can, then the users can check if it's a candidate for sharing or not. The code is simplified too and fewer corner cases: such as stable_node and stable_node_dup can't be NULL if returned tree_folio is not NULL. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Chengming Zhou <[email protected]> Cc: Andrea Arcangeli <[email protected]> Cc: David Hildenbrand <[email protected]> Cc: Hugh Dickins <[email protected]> Cc: Stefan Roesch <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent d58a361 commit a0b856b

File tree

1 file changed

+27
-125
lines changed

1 file changed

+27
-125
lines changed

mm/ksm.c

Lines changed: 27 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1659,7 +1659,6 @@ static struct folio *stable_node_dup(struct ksm_stable_node **_stable_node_dup,
16591659
struct ksm_stable_node *dup, *found = NULL, *stable_node = *_stable_node;
16601660
struct hlist_node *hlist_safe;
16611661
struct folio *folio, *tree_folio = NULL;
1662-
int nr = 0;
16631662
int found_rmap_hlist_len;
16641663

16651664
if (!prune_stale_stable_nodes ||
@@ -1686,33 +1685,26 @@ static struct folio *stable_node_dup(struct ksm_stable_node **_stable_node_dup,
16861685
folio = ksm_get_folio(dup, KSM_GET_FOLIO_NOLOCK);
16871686
if (!folio)
16881687
continue;
1689-
nr += 1;
1690-
if (is_page_sharing_candidate(dup)) {
1691-
if (!found ||
1692-
dup->rmap_hlist_len > found_rmap_hlist_len) {
1693-
if (found)
1694-
folio_put(tree_folio);
1695-
found = dup;
1696-
found_rmap_hlist_len = found->rmap_hlist_len;
1697-
tree_folio = folio;
1698-
1699-
/* skip put_page for found dup */
1700-
if (!prune_stale_stable_nodes)
1701-
break;
1702-
continue;
1703-
}
1688+
/* Pick the best candidate if possible. */
1689+
if (!found || (is_page_sharing_candidate(dup) &&
1690+
(!is_page_sharing_candidate(found) ||
1691+
dup->rmap_hlist_len > found_rmap_hlist_len))) {
1692+
if (found)
1693+
folio_put(tree_folio);
1694+
found = dup;
1695+
found_rmap_hlist_len = found->rmap_hlist_len;
1696+
tree_folio = folio;
1697+
/* skip put_page for found candidate */
1698+
if (!prune_stale_stable_nodes &&
1699+
is_page_sharing_candidate(found))
1700+
break;
1701+
continue;
17041702
}
17051703
folio_put(folio);
17061704
}
17071705

17081706
if (found) {
1709-
/*
1710-
* nr is counting all dups in the chain only if
1711-
* prune_stale_stable_nodes is true, otherwise we may
1712-
* break the loop at nr == 1 even if there are
1713-
* multiple entries.
1714-
*/
1715-
if (prune_stale_stable_nodes && nr == 1) {
1707+
if (hlist_is_singular_node(&found->hlist_dup, &stable_node->hlist)) {
17161708
/*
17171709
* If there's not just one entry it would
17181710
* corrupt memory, better BUG_ON. In KSM
@@ -1764,25 +1756,15 @@ static struct folio *stable_node_dup(struct ksm_stable_node **_stable_node_dup,
17641756
hlist_add_head(&found->hlist_dup,
17651757
&stable_node->hlist);
17661758
}
1759+
} else {
1760+
/* Its hlist must be empty if no one found. */
1761+
free_stable_node_chain(stable_node, root);
17671762
}
17681763

17691764
*_stable_node_dup = found;
17701765
return tree_folio;
17711766
}
17721767

1773-
static struct ksm_stable_node *stable_node_dup_any(struct ksm_stable_node *stable_node,
1774-
struct rb_root *root)
1775-
{
1776-
if (!is_stable_node_chain(stable_node))
1777-
return stable_node;
1778-
if (hlist_empty(&stable_node->hlist)) {
1779-
free_stable_node_chain(stable_node, root);
1780-
return NULL;
1781-
}
1782-
return hlist_entry(stable_node->hlist.first,
1783-
typeof(*stable_node), hlist_dup);
1784-
}
1785-
17861768
/*
17871769
* Like for ksm_get_folio, this function can free the *_stable_node and
17881770
* *_stable_node_dup if the returned tree_page is NULL.
@@ -1803,17 +1785,10 @@ static struct folio *__stable_node_chain(struct ksm_stable_node **_stable_node_d
18031785
bool prune_stale_stable_nodes)
18041786
{
18051787
struct ksm_stable_node *stable_node = *_stable_node;
1788+
18061789
if (!is_stable_node_chain(stable_node)) {
1807-
if (is_page_sharing_candidate(stable_node)) {
1808-
*_stable_node_dup = stable_node;
1809-
return ksm_get_folio(stable_node, KSM_GET_FOLIO_NOLOCK);
1810-
}
1811-
/*
1812-
* _stable_node_dup set to NULL means the stable_node
1813-
* reached the ksm_max_page_sharing limit.
1814-
*/
1815-
*_stable_node_dup = NULL;
1816-
return NULL;
1790+
*_stable_node_dup = stable_node;
1791+
return ksm_get_folio(stable_node, KSM_GET_FOLIO_NOLOCK);
18171792
}
18181793
return stable_node_dup(_stable_node_dup, _stable_node, root,
18191794
prune_stale_stable_nodes);
@@ -1827,16 +1802,10 @@ static __always_inline struct folio *chain_prune(struct ksm_stable_node **s_n_d,
18271802
}
18281803

18291804
static __always_inline struct folio *chain(struct ksm_stable_node **s_n_d,
1830-
struct ksm_stable_node *s_n,
1805+
struct ksm_stable_node **s_n,
18311806
struct rb_root *root)
18321807
{
1833-
struct ksm_stable_node *old_stable_node = s_n;
1834-
struct folio *tree_folio;
1835-
1836-
tree_folio = __stable_node_chain(s_n_d, &s_n, root, false);
1837-
/* not pruning dups so s_n cannot have changed */
1838-
VM_BUG_ON(s_n != old_stable_node);
1839-
return tree_folio;
1808+
return __stable_node_chain(s_n_d, s_n, root, false);
18401809
}
18411810

18421811
/*
@@ -1854,7 +1823,7 @@ static struct page *stable_tree_search(struct page *page)
18541823
struct rb_root *root;
18551824
struct rb_node **new;
18561825
struct rb_node *parent;
1857-
struct ksm_stable_node *stable_node, *stable_node_dup, *stable_node_any;
1826+
struct ksm_stable_node *stable_node, *stable_node_dup;
18581827
struct ksm_stable_node *page_node;
18591828
struct folio *folio;
18601829

@@ -1878,45 +1847,7 @@ static struct page *stable_tree_search(struct page *page)
18781847

18791848
cond_resched();
18801849
stable_node = rb_entry(*new, struct ksm_stable_node, node);
1881-
stable_node_any = NULL;
18821850
tree_folio = chain_prune(&stable_node_dup, &stable_node, root);
1883-
/*
1884-
* NOTE: stable_node may have been freed by
1885-
* chain_prune() if the returned stable_node_dup is
1886-
* not NULL. stable_node_dup may have been inserted in
1887-
* the rbtree instead as a regular stable_node (in
1888-
* order to collapse the stable_node chain if a single
1889-
* stable_node dup was found in it). In such case the
1890-
* stable_node is overwritten by the callee to point
1891-
* to the stable_node_dup that was collapsed in the
1892-
* stable rbtree and stable_node will be equal to
1893-
* stable_node_dup like if the chain never existed.
1894-
*/
1895-
if (!stable_node_dup) {
1896-
/*
1897-
* Either all stable_node dups were full in
1898-
* this stable_node chain, or this chain was
1899-
* empty and should be rb_erased.
1900-
*/
1901-
stable_node_any = stable_node_dup_any(stable_node,
1902-
root);
1903-
if (!stable_node_any) {
1904-
/* rb_erase just run */
1905-
goto again;
1906-
}
1907-
/*
1908-
* Take any of the stable_node dups page of
1909-
* this stable_node chain to let the tree walk
1910-
* continue. All KSM pages belonging to the
1911-
* stable_node dups in a stable_node chain
1912-
* have the same content and they're
1913-
* write protected at all times. Any will work
1914-
* fine to continue the walk.
1915-
*/
1916-
tree_folio = ksm_get_folio(stable_node_any,
1917-
KSM_GET_FOLIO_NOLOCK);
1918-
}
1919-
VM_BUG_ON(!stable_node_dup ^ !!stable_node_any);
19201851
if (!tree_folio) {
19211852
/*
19221853
* If we walked over a stale stable_node,
@@ -1954,7 +1885,7 @@ static struct page *stable_tree_search(struct page *page)
19541885
goto chain_append;
19551886
}
19561887

1957-
if (!stable_node_dup) {
1888+
if (!is_page_sharing_candidate(stable_node_dup)) {
19581889
/*
19591890
* If the stable_node is a chain and
19601891
* we got a payload match in memcmp
@@ -2063,9 +1994,6 @@ static struct page *stable_tree_search(struct page *page)
20631994
return &folio->page;
20641995

20651996
chain_append:
2066-
/* stable_node_dup could be null if it reached the limit */
2067-
if (!stable_node_dup)
2068-
stable_node_dup = stable_node_any;
20691997
/*
20701998
* If stable_node was a chain and chain_prune collapsed it,
20711999
* stable_node has been updated to be the new regular
@@ -2110,7 +2038,7 @@ static struct ksm_stable_node *stable_tree_insert(struct folio *kfolio)
21102038
struct rb_root *root;
21112039
struct rb_node **new;
21122040
struct rb_node *parent;
2113-
struct ksm_stable_node *stable_node, *stable_node_dup, *stable_node_any;
2041+
struct ksm_stable_node *stable_node, *stable_node_dup;
21142042
bool need_chain = false;
21152043

21162044
kpfn = folio_pfn(kfolio);
@@ -2126,33 +2054,7 @@ static struct ksm_stable_node *stable_tree_insert(struct folio *kfolio)
21262054

21272055
cond_resched();
21282056
stable_node = rb_entry(*new, struct ksm_stable_node, node);
2129-
stable_node_any = NULL;
2130-
tree_folio = chain(&stable_node_dup, stable_node, root);
2131-
if (!stable_node_dup) {
2132-
/*
2133-
* Either all stable_node dups were full in
2134-
* this stable_node chain, or this chain was
2135-
* empty and should be rb_erased.
2136-
*/
2137-
stable_node_any = stable_node_dup_any(stable_node,
2138-
root);
2139-
if (!stable_node_any) {
2140-
/* rb_erase just run */
2141-
goto again;
2142-
}
2143-
/*
2144-
* Take any of the stable_node dups page of
2145-
* this stable_node chain to let the tree walk
2146-
* continue. All KSM pages belonging to the
2147-
* stable_node dups in a stable_node chain
2148-
* have the same content and they're
2149-
* write protected at all times. Any will work
2150-
* fine to continue the walk.
2151-
*/
2152-
tree_folio = ksm_get_folio(stable_node_any,
2153-
KSM_GET_FOLIO_NOLOCK);
2154-
}
2155-
VM_BUG_ON(!stable_node_dup ^ !!stable_node_any);
2057+
tree_folio = chain(&stable_node_dup, &stable_node, root);
21562058
if (!tree_folio) {
21572059
/*
21582060
* If we walked over a stale stable_node,

0 commit comments

Comments
 (0)