aboutsummaryrefslogtreecommitdiffstats
path: root/mm/ksm.c
diff options
context:
space:
mode:
authorAndrea Arcangeli <aarcange@redhat.com>2017-07-06 18:37:02 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-06 19:24:31 -0400
commit0ba1d0f7c41cdab306a3d30e036bc393c3ebba7e (patch)
tree3e236e2b9d3c5c6223d95525dc6277d45d51387a /mm/ksm.c
parentb4fecc67cc569b14301f5a1111363d5818b8da5e (diff)
ksm: cleanup stable_node chain collapse case
Patch series "KSMscale cleanup/optimizations". There are no fixes here it's just minor cleanups and optimizations. 1/3 removes makes the "fix" for the stale stable_node fall in the standard case without introducing new cases. Setting stable_node to NULL was marginally safer, but stale pointer is still wiped from the caller, this looks cleaner. 2/3 should fix the false positive from Dan's static checker. 3/3 is a microoptimization to apply the the refile of future merge candidate dups at the head of the chain in all cases and to skip it in one case where we did it and but it was a noop (to avoid checking if it was already at the head but now we've to check it anyway so it got optimized away). This patch (of 3): When the stable_node chain is collapsed we can as well set the caller stable_node to match the returned stable_node_dup in chain_prune(). This way the collapse case becomes indistinguishable from the regular stable_node case and we can remove two branches from the KSM page migration handling slow paths. While it was all correct this looks cleaner (and faster) as the caller has to deal with fewer special cases. Link: http://lkml.kernel.org/r/20170518173721.22316-2-aarcange@redhat.com Signed-off-by: Andrea Arcangeli <aarcange@redhat.com> Cc: Evgheni Dereveanchin <ederevea@redhat.com> Cc: Andrey Ryabinin <aryabinin@virtuozzo.com> Cc: Petr Holasek <pholasek@redhat.com> Cc: Hugh Dickins <hughd@google.com> Cc: Arjan van de Ven <arjan@linux.intel.com> Cc: Davidlohr Bueso <dave@stgolabs.net> Cc: Gavin Guo <gavin.guo@canonical.com> Cc: Jay Vosburgh <jay.vosburgh@canonical.com> Cc: Mel Gorman <mgorman@techsingularity.net> Cc: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/ksm.c')
-rw-r--r--mm/ksm.c50
1 files changed, 28 insertions, 22 deletions
diff --git a/mm/ksm.c b/mm/ksm.c
index 5621840401c0..64b054641f39 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1392,14 +1392,18 @@ static struct stable_node *stable_node_dup(struct stable_node **_stable_node,
1392 ksm_stable_node_chains--; 1392 ksm_stable_node_chains--;
1393 ksm_stable_node_dups--; 1393 ksm_stable_node_dups--;
1394 /* 1394 /*
1395 * NOTE: the caller depends on the 1395 * NOTE: the caller depends on the stable_node
1396 * *_stable_node to become NULL if the chain 1396 * to be equal to stable_node_dup if the chain
1397 * was collapsed. Enforce that if anything 1397 * was collapsed.
1398 * uses a stale (freed) stable_node chain a
1399 * visible crash will materialize (instead of
1400 * an use after free).
1401 */ 1398 */
1402 *_stable_node = stable_node = NULL; 1399 *_stable_node = found;
1400 /*
1401 * Just for robustneess as stable_node is
1402 * otherwise left as a stable pointer, the
1403 * compiler shall optimize it away at build
1404 * time.
1405 */
1406 stable_node = NULL;
1403 } else if (__is_page_sharing_candidate(found, 1)) { 1407 } else if (__is_page_sharing_candidate(found, 1)) {
1404 /* 1408 /*
1405 * Refile our candidate at the head 1409 * Refile our candidate at the head
@@ -1505,7 +1509,11 @@ again:
1505 * not NULL. stable_node_dup may have been inserted in 1509 * not NULL. stable_node_dup may have been inserted in
1506 * the rbtree instead as a regular stable_node (in 1510 * the rbtree instead as a regular stable_node (in
1507 * order to collapse the stable_node chain if a single 1511 * order to collapse the stable_node chain if a single
1508 * stable_node dup was found in it). 1512 * stable_node dup was found in it). In such case the
1513 * stable_node is overwritten by the calleee to point
1514 * to the stable_node_dup that was collapsed in the
1515 * stable rbtree and stable_node will be equal to
1516 * stable_node_dup like if the chain never existed.
1509 */ 1517 */
1510 if (!stable_node_dup) { 1518 if (!stable_node_dup) {
1511 /* 1519 /*
@@ -1623,15 +1631,13 @@ out:
1623replace: 1631replace:
1624 /* 1632 /*
1625 * If stable_node was a chain and chain_prune collapsed it, 1633 * If stable_node was a chain and chain_prune collapsed it,
1626 * stable_node will be NULL here. In that case the 1634 * stable_node has been updated to be the new regular
1627 * stable_node_dup is the regular stable_node that has 1635 * stable_node. A collapse of the chain is indistinguishable
1628 * replaced the chain. If stable_node is not NULL and equal to 1636 * from the case there was no chain in the stable
1629 * stable_node_dup there was no chain and stable_node_dup is 1637 * rbtree. Otherwise stable_node is the chain and
1630 * the regular stable_node in the stable rbtree. Otherwise 1638 * stable_node_dup is the dup to replace.
1631 * stable_node is the chain and stable_node_dup is the dup to
1632 * replace.
1633 */ 1639 */
1634 if (!stable_node || stable_node_dup == stable_node) { 1640 if (stable_node_dup == stable_node) {
1635 VM_BUG_ON(is_stable_node_chain(stable_node_dup)); 1641 VM_BUG_ON(is_stable_node_chain(stable_node_dup));
1636 VM_BUG_ON(is_stable_node_dup(stable_node_dup)); 1642 VM_BUG_ON(is_stable_node_dup(stable_node_dup));
1637 /* there is no chain */ 1643 /* there is no chain */
@@ -1676,13 +1682,13 @@ chain_append:
1676 stable_node_dup = stable_node_any; 1682 stable_node_dup = stable_node_any;
1677 /* 1683 /*
1678 * If stable_node was a chain and chain_prune collapsed it, 1684 * If stable_node was a chain and chain_prune collapsed it,
1679 * stable_node will be NULL here. In that case the 1685 * stable_node has been updated to be the new regular
1680 * stable_node_dup is the regular stable_node that has 1686 * stable_node. A collapse of the chain is indistinguishable
1681 * replaced the chain. If stable_node is not NULL and equal to 1687 * from the case there was no chain in the stable
1682 * stable_node_dup there was no chain and stable_node_dup is 1688 * rbtree. Otherwise stable_node is the chain and
1683 * the regular stable_node in the stable rbtree. 1689 * stable_node_dup is the dup to replace.
1684 */ 1690 */
1685 if (!stable_node || stable_node_dup == stable_node) { 1691 if (stable_node_dup == stable_node) {
1686 VM_BUG_ON(is_stable_node_chain(stable_node_dup)); 1692 VM_BUG_ON(is_stable_node_chain(stable_node_dup));
1687 VM_BUG_ON(is_stable_node_dup(stable_node_dup)); 1693 VM_BUG_ON(is_stable_node_dup(stable_node_dup));
1688 /* chain is missing so create it */ 1694 /* chain is missing so create it */