All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/4] Refactor node_states_check_changes_online/offline
@ 2018-09-21 13:26 Oscar Salvador
  2018-09-21 13:26 ` [PATCH v2 1/4] mm/memory_hotplug: Spare unnecessary calls to node_set_state Oscar Salvador
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Oscar Salvador @ 2018-09-21 13:26 UTC (permalink / raw)
  To: akpm
  Cc: mhocko, dan.j.williams, david, Pavel.Tatashin, Jonathan.Cameron,
	yasu.isimatu, malat, linux-mm, linux-kernel, Oscar Salvador

From: Oscar Salvador <osalvador@suse.de>

v1 -> v2:
        - Address feedback from Pavel
        - Re-write patch4 his way, as it is better
        - Add Reviewed-by from Pavel

---

This patchset refactors/clean ups node_states_check_changes_online/offline
functions together with node_states_set/clear_node.

The main reason behind this patchset is that currently, these
functions are suboptimal and confusing.

For example, they contain wrong statements like:

if (N_MEMORY == N_NORMAL_MEMORY)
if (N_MEMORY =! N_NORMAL_MEMORY)
if (N_MEMORY != N_HIGH_MEMORY)
if (N_MEMORY == N_HIGH_MEMORY)

These comparasions are wrong, as N_MEMORY will never be equal
to either N_NORMAL_MEMORY or N_HIGH_MEMORY.
Although the statements do not "affect" the flow because in the way
they are placed, they are completely wrong and confusing.

I caught another misuse of this in [1].

Another thing that this patchset addresses is the fact that
some functions get called twice, or even unconditionally, without
any need.

Examples of this are:

- node_states_set_node()->node_set_state(node, N_MEMORY)

* node_states_set_node() gets called whenever we online pages,
  so we end up calling node_set_state(node, N_MEMORY) everytime.
  To avoid this, we should check if the node is already in node_state[N_MEMORY].

- node_states_set_node()->node_set_state(node, N_HIGH_MEMORY)

* On !CONFIG_HIGH_MEMORY, N_HIGH_MEMORY == N_NORMAL_MEMORY,
  but the current code sets:
  status_change_nid_high = status_change_nid_normal
  This means that we will call node_set_state(node, N_NORMAL_MEMORY) twice.
  The fix here is to set status_change_nid_normal = -1 on such systems,
  so we skip the second call.

[1] https://patchwork.kernel.org/patch/10579155/

Oscar Salvador (4):
  mm/memory_hotplug: Spare unnecessary calls to node_set_state
  mm/memory_hotplug: Tidy up node_states_clear_node
  mm/memory_hotplug: Simplify node_states_check_changes_online
  mm/memory_hotplug: Clean up node_states_check_changes_offline

 mm/memory_hotplug.c | 146 ++++++++++++++--------------------------------------
 1 file changed, 40 insertions(+), 106 deletions(-)

-- 
2.13.6


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 1/4] mm/memory_hotplug: Spare unnecessary calls to node_set_state
  2018-09-21 13:26 [PATCH v2 0/4] Refactor node_states_check_changes_online/offline Oscar Salvador
@ 2018-09-21 13:26 ` Oscar Salvador
  2018-09-21 13:26 ` [PATCH v2 2/4] mm/memory_hotplug: Tidy up node_states_clear_node Oscar Salvador
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Oscar Salvador @ 2018-09-21 13:26 UTC (permalink / raw)
  To: akpm
  Cc: mhocko, dan.j.williams, david, Pavel.Tatashin, Jonathan.Cameron,
	yasu.isimatu, malat, linux-mm, linux-kernel, Oscar Salvador

From: Oscar Salvador <osalvador@suse.de>

In node_states_check_changes_online, we check if the node will
have to be set for any of the N_*_MEMORY states after the pages
have been onlined.

Later on, we perform the activation in node_states_set_node.
Currently, in node_states_set_node we set the node to N_MEMORY
unconditionally.
This means that we call node_set_state for N_MEMORY every time
pages go online, but we only need to do it if the node has not yet been
set for N_MEMORY.

Fix this by checking status_change_nid.

Signed-off-by: Oscar Salvador <osalvador@suse.de>
Reviewed-by: Pavel Tatashin <pavel.tatashin@microsoft.com>
---
 mm/memory_hotplug.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 38d94b703e9d..63facfc57224 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -753,7 +753,8 @@ static void node_states_set_node(int node, struct memory_notify *arg)
 	if (arg->status_change_nid_high >= 0)
 		node_set_state(node, N_HIGH_MEMORY);
 
-	node_set_state(node, N_MEMORY);
+	if (arg->status_change_nid >= 0)
+		node_set_state(node, N_MEMORY);
 }
 
 static void __meminit resize_zone_range(struct zone *zone, unsigned long start_pfn,
-- 
2.13.6


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 2/4] mm/memory_hotplug: Tidy up node_states_clear_node
  2018-09-21 13:26 [PATCH v2 0/4] Refactor node_states_check_changes_online/offline Oscar Salvador
  2018-09-21 13:26 ` [PATCH v2 1/4] mm/memory_hotplug: Spare unnecessary calls to node_set_state Oscar Salvador
@ 2018-09-21 13:26 ` Oscar Salvador
  2018-09-21 13:26 ` [PATCH v2 3/4] mm/memory_hotplug: Simplify node_states_check_changes_online Oscar Salvador
  2018-09-21 13:26 ` [PATCH v2 4/4] mm/memory_hotplug: Clean up node_states_check_changes_offline Oscar Salvador
  3 siblings, 0 replies; 6+ messages in thread
From: Oscar Salvador @ 2018-09-21 13:26 UTC (permalink / raw)
  To: akpm
  Cc: mhocko, dan.j.williams, david, Pavel.Tatashin, Jonathan.Cameron,
	yasu.isimatu, malat, linux-mm, linux-kernel, Oscar Salvador

From: Oscar Salvador <osalvador@suse.de>

node_states_clear has the following if statements:

if ((N_MEMORY != N_NORMAL_MEMORY) &&
    (arg->status_change_nid_high >= 0))
        ...

if ((N_MEMORY != N_HIGH_MEMORY) &&
    (arg->status_change_nid >= 0))
        ...

N_MEMORY can never be equal to neither N_NORMAL_MEMORY nor
N_HIGH_MEMORY.

Similar problem was found in [1].
Since this is wrong, let us get rid of it.

[1] https://patchwork.kernel.org/patch/10579155/

Signed-off-by: Oscar Salvador <osalvador@suse.de>
Reviewed-by: Pavel Tatashin <pavel.tatashin@microsoft.com>
---
 mm/memory_hotplug.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 63facfc57224..561c44761f95 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1582,12 +1582,10 @@ static void node_states_clear_node(int node, struct memory_notify *arg)
 	if (arg->status_change_nid_normal >= 0)
 		node_clear_state(node, N_NORMAL_MEMORY);
 
-	if ((N_MEMORY != N_NORMAL_MEMORY) &&
-	    (arg->status_change_nid_high >= 0))
+	if (arg->status_change_nid_high >= 0)
 		node_clear_state(node, N_HIGH_MEMORY);
 
-	if ((N_MEMORY != N_HIGH_MEMORY) &&
-	    (arg->status_change_nid >= 0))
+	if (arg->status_change_nid >= 0)
 		node_clear_state(node, N_MEMORY);
 }
 
-- 
2.13.6


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 3/4] mm/memory_hotplug: Simplify node_states_check_changes_online
  2018-09-21 13:26 [PATCH v2 0/4] Refactor node_states_check_changes_online/offline Oscar Salvador
  2018-09-21 13:26 ` [PATCH v2 1/4] mm/memory_hotplug: Spare unnecessary calls to node_set_state Oscar Salvador
  2018-09-21 13:26 ` [PATCH v2 2/4] mm/memory_hotplug: Tidy up node_states_clear_node Oscar Salvador
@ 2018-09-21 13:26 ` Oscar Salvador
  2018-09-21 14:25   ` Pasha Tatashin
  2018-09-21 13:26 ` [PATCH v2 4/4] mm/memory_hotplug: Clean up node_states_check_changes_offline Oscar Salvador
  3 siblings, 1 reply; 6+ messages in thread
From: Oscar Salvador @ 2018-09-21 13:26 UTC (permalink / raw)
  To: akpm
  Cc: mhocko, dan.j.williams, david, Pavel.Tatashin, Jonathan.Cameron,
	yasu.isimatu, malat, linux-mm, linux-kernel, Oscar Salvador

From: Oscar Salvador <osalvador@suse.de>

While looking at node_states_check_changes_online, I stumbled
upon some confusing things.

Right after entering the function, we find this:

if (N_MEMORY == N_NORMAL_MEMORY)
        zone_last = ZONE_MOVABLE;

This is wrong.
N_MEMORY cannot really be equal to N_NORMAL_MEMORY.
My guess is that this wanted to be something like:

if (N_NORMAL_MEMORY == N_HIGH_MEMORY)

to check if we have CONFIG_HIGHMEM.

Later on, in the CONFIG_HIGHMEM block, we have:

if (N_MEMORY == N_HIGH_MEMORY)
        zone_last = ZONE_MOVABLE;

Again, this is wrong, and will never be evaluated to true.

Besides removing these wrong if statements, I simplified
the function a bit.

Signed-off-by: Oscar Salvador <osalvador@suse.de>
Suggested-by: Pavel Tatashin <pavel.tatashin@microsoft.com>
---
 mm/memory_hotplug.c | 57 +++++++----------------------------------------------
 1 file changed, 7 insertions(+), 50 deletions(-)

diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 561c44761f95..eadd149eb7bc 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -687,62 +687,19 @@ static void node_states_check_changes_online(unsigned long nr_pages,
 	struct zone *zone, struct memory_notify *arg)
 {
 	int nid = zone_to_nid(zone);
-	enum zone_type zone_last = ZONE_NORMAL;
 
-	/*
-	 * If we have HIGHMEM or movable node, node_states[N_NORMAL_MEMORY]
-	 * contains nodes which have zones of 0...ZONE_NORMAL,
-	 * set zone_last to ZONE_NORMAL.
-	 *
-	 * If we don't have HIGHMEM nor movable node,
-	 * node_states[N_NORMAL_MEMORY] contains nodes which have zones of
-	 * 0...ZONE_MOVABLE, set zone_last to ZONE_MOVABLE.
-	 */
-	if (N_MEMORY == N_NORMAL_MEMORY)
-		zone_last = ZONE_MOVABLE;
+	arg->status_change_nid = -1;
+	arg->status_change_nid_normal = -1;
+	arg->status_change_nid_high = -1;
 
-	/*
-	 * if the memory to be online is in a zone of 0...zone_last, and
-	 * the zones of 0...zone_last don't have memory before online, we will
-	 * need to set the node to node_states[N_NORMAL_MEMORY] after
-	 * the memory is online.
-	 */
-	if (zone_idx(zone) <= zone_last && !node_state(nid, N_NORMAL_MEMORY))
+	if (!node_state(nid, N_MEMORY))
+		arg->status_change_nid = nid;
+	if (zone_idx(zone) <= ZONE_NORMAL && !node_state(nid, N_NORMAL_MEMORY))
 		arg->status_change_nid_normal = nid;
-	else
-		arg->status_change_nid_normal = -1;
-
 #ifdef CONFIG_HIGHMEM
-	/*
-	 * If we have movable node, node_states[N_HIGH_MEMORY]
-	 * contains nodes which have zones of 0...ZONE_HIGHMEM,
-	 * set zone_last to ZONE_HIGHMEM.
-	 *
-	 * If we don't have movable node, node_states[N_NORMAL_MEMORY]
-	 * contains nodes which have zones of 0...ZONE_MOVABLE,
-	 * set zone_last to ZONE_MOVABLE.
-	 */
-	zone_last = ZONE_HIGHMEM;
-	if (N_MEMORY == N_HIGH_MEMORY)
-		zone_last = ZONE_MOVABLE;
-
-	if (zone_idx(zone) <= zone_last && !node_state(nid, N_HIGH_MEMORY))
+	if (zone_idx(zone) <= N_HIGH_MEMORY && !node_state(nid, N_HIGH_MEMORY))
 		arg->status_change_nid_high = nid;
-	else
-		arg->status_change_nid_high = -1;
-#else
-	arg->status_change_nid_high = arg->status_change_nid_normal;
 #endif
-
-	/*
-	 * if the node don't have memory befor online, we will need to
-	 * set the node to node_states[N_MEMORY] after the memory
-	 * is online.
-	 */
-	if (!node_state(nid, N_MEMORY))
-		arg->status_change_nid = nid;
-	else
-		arg->status_change_nid = -1;
 }
 
 static void node_states_set_node(int node, struct memory_notify *arg)
-- 
2.13.6


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 4/4] mm/memory_hotplug: Clean up node_states_check_changes_offline
  2018-09-21 13:26 [PATCH v2 0/4] Refactor node_states_check_changes_online/offline Oscar Salvador
                   ` (2 preceding siblings ...)
  2018-09-21 13:26 ` [PATCH v2 3/4] mm/memory_hotplug: Simplify node_states_check_changes_online Oscar Salvador
@ 2018-09-21 13:26 ` Oscar Salvador
  3 siblings, 0 replies; 6+ messages in thread
From: Oscar Salvador @ 2018-09-21 13:26 UTC (permalink / raw)
  To: akpm
  Cc: mhocko, dan.j.williams, david, Pavel.Tatashin, Jonathan.Cameron,
	yasu.isimatu, malat, linux-mm, linux-kernel, Oscar Salvador

From: Oscar Salvador <osalvador@suse.de>

This patch, as the previous one, gets rid of the wrong if statements.
While at it, I realized that the comments are sometimes very confusing,
to say the least, and wrong.
For example:

___
zone_last = ZONE_MOVABLE;

/*
 * check whether node_states[N_HIGH_MEMORY] will be changed
 * If we try to offline the last present @nr_pages from the node,
 * we can determind we will need to clear the node from
 * node_states[N_HIGH_MEMORY].
 */

for (; zt <= zone_last; zt++)
        present_pages += pgdat->node_zones[zt].present_pages;
if (nr_pages >= present_pages)
        arg->status_change_nid = zone_to_nid(zone);
else
        arg->status_change_nid = -1;
___

In case the node gets empry, it must be removed from N_MEMORY.
We already check N_HIGH_MEMORY a bit above within the CONFIG_HIGHMEM
ifdef code.
Not to say that status_change_nid is for N_MEMORY, and not for
N_HIGH_MEMORY.

So I re-wrote some of the comments to what I think is better.

Signed-off-by: Oscar Salvador <osalvador@suse.de>
Reviewed-by: Pavel Tatashin <pavel.tatashin@microsoft.com>
---
 mm/memory_hotplug.c | 80 +++++++++++++++++++----------------------------------
 1 file changed, 29 insertions(+), 51 deletions(-)

diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index eadd149eb7bc..f19b63f024c9 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1463,75 +1463,53 @@ static void node_states_check_changes_offline(unsigned long nr_pages,
 {
 	struct pglist_data *pgdat = zone->zone_pgdat;
 	unsigned long present_pages = 0;
-	enum zone_type zt, zone_last = ZONE_NORMAL;
+	enum zone_type zt;
 
-	/*
-	 * If we have HIGHMEM or movable node, node_states[N_NORMAL_MEMORY]
-	 * contains nodes which have zones of 0...ZONE_NORMAL,
-	 * set zone_last to ZONE_NORMAL.
-	 *
-	 * If we don't have HIGHMEM nor movable node,
-	 * node_states[N_NORMAL_MEMORY] contains nodes which have zones of
-	 * 0...ZONE_MOVABLE, set zone_last to ZONE_MOVABLE.
-	 */
-	if (N_MEMORY == N_NORMAL_MEMORY)
-		zone_last = ZONE_MOVABLE;
+	arg->status_change_nid = -1;	
+	arg->status_change_nid_normal = -1;
+	arg->status_change_nid_high = -1;
 
 	/*
-	 * check whether node_states[N_NORMAL_MEMORY] will be changed.
-	 * If the memory to be offline is in a zone of 0...zone_last,
-	 * and it is the last present memory, 0...zone_last will
-	 * become empty after offline , thus we can determind we will
-	 * need to clear the node from node_states[N_NORMAL_MEMORY].
+	 * Check whether node_states[N_NORMAL_MEMORY] will be changed.
+	 * If the memory to be offline is within the range
+	 * [0..ZONE_NORMAL], and it is the last present memory there,
+	 * the zones in that range will become empty after the offlining,
+	 * thus we can determine that we need to clear the node from
+	 * node_states[N_NORMAL_MEMORY].
 	 */
-	for (zt = 0; zt <= zone_last; zt++)
+	for (zt = 0; zt <= ZONE_NORMAL; zt++)
 		present_pages += pgdat->node_zones[zt].present_pages;
-	if (zone_idx(zone) <= zone_last && nr_pages >= present_pages)
+	if (zone_idx(zone) <= ZONE_NORMAL && nr_pages >= present_pages)
 		arg->status_change_nid_normal = zone_to_nid(zone);
-	else
-		arg->status_change_nid_normal = -1;
 
 #ifdef CONFIG_HIGHMEM
 	/*
-	 * If we have movable node, node_states[N_HIGH_MEMORY]
-	 * contains nodes which have zones of 0...ZONE_HIGHMEM,
-	 * set zone_last to ZONE_HIGHMEM.
-	 *
-	 * If we don't have movable node, node_states[N_NORMAL_MEMORY]
-	 * contains nodes which have zones of 0...ZONE_MOVABLE,
-	 * set zone_last to ZONE_MOVABLE.
+	 * node_states[N_HIGH_MEMORY] contains nodes which
+	 * have normal memory or high memory.
+	 * Here we add the present_pages belonging to ZONE_HIGHMEM.
+	 * If the zone is within the range of [0..ZONE_HIGHMEM), and
+	 * we determine that the zones in that range become empty,
+	 * we need to clear the node for N_HIGH_MEMORY.
 	 */
-	zone_last = ZONE_HIGHMEM;
-	if (N_MEMORY == N_HIGH_MEMORY)
-		zone_last = ZONE_MOVABLE;
-
-	for (; zt <= zone_last; zt++)
-		present_pages += pgdat->node_zones[zt].present_pages;
-	if (zone_idx(zone) <= zone_last && nr_pages >= present_pages)
+	present_pages += pgdat->node_zones[ZONE_HIGHMEM].present_pages;
+	if (zone_idx(zone) <= ZONE_HIGHMEM && nr_pages >= present_pages)
 		arg->status_change_nid_high = zone_to_nid(zone);
-	else
-		arg->status_change_nid_high = -1;
-#else
-	arg->status_change_nid_high = arg->status_change_nid_normal;
 #endif
 
 	/*
-	 * node_states[N_HIGH_MEMORY] contains nodes which have 0...ZONE_MOVABLE
+	 * We have accounted the pages from [0..ZONE_NORMAL), and
+	 * in case of CONFIG_HIGHMEM the pages from ZONE_HIGHMEM
+	 * as well.
+	 * Here we count the possible pages from ZONE_MOVABLE.
+	 * If after having accounted all the pages, we see that the nr_pages
+	 * to be offlined is over or equal to the accounted pages,
+	 * we know that the node will become empty, and so, we can clear
+	 * it for N_MEMORY as well.
 	 */
-	zone_last = ZONE_MOVABLE;
+	present_pages += pgdat->node_zones[ZONE_MOVABLE].present_pages;
 
-	/*
-	 * check whether node_states[N_HIGH_MEMORY] will be changed
-	 * If we try to offline the last present @nr_pages from the node,
-	 * we can determind we will need to clear the node from
-	 * node_states[N_HIGH_MEMORY].
-	 */
-	for (; zt <= zone_last; zt++)
-		present_pages += pgdat->node_zones[zt].present_pages;
 	if (nr_pages >= present_pages)
 		arg->status_change_nid = zone_to_nid(zone);
-	else
-		arg->status_change_nid = -1;
 }
 
 static void node_states_clear_node(int node, struct memory_notify *arg)
-- 
2.13.6


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 3/4] mm/memory_hotplug: Simplify node_states_check_changes_online
  2018-09-21 13:26 ` [PATCH v2 3/4] mm/memory_hotplug: Simplify node_states_check_changes_online Oscar Salvador
@ 2018-09-21 14:25   ` Pasha Tatashin
  0 siblings, 0 replies; 6+ messages in thread
From: Pasha Tatashin @ 2018-09-21 14:25 UTC (permalink / raw)
  To: Oscar Salvador, akpm
  Cc: mhocko, dan.j.williams, david, Jonathan.Cameron, yasu.isimatu,
	malat, linux-mm, linux-kernel, Oscar Salvador



On 9/21/18 9:26 AM, Oscar Salvador wrote:
> From: Oscar Salvador <osalvador@suse.de>
> 
> While looking at node_states_check_changes_online, I stumbled
> upon some confusing things.
> 
> Right after entering the function, we find this:
> 
> if (N_MEMORY == N_NORMAL_MEMORY)
>         zone_last = ZONE_MOVABLE;
> 
> This is wrong.
> N_MEMORY cannot really be equal to N_NORMAL_MEMORY.
> My guess is that this wanted to be something like:
> 
> if (N_NORMAL_MEMORY == N_HIGH_MEMORY)
> 
> to check if we have CONFIG_HIGHMEM.
> 
> Later on, in the CONFIG_HIGHMEM block, we have:
> 
> if (N_MEMORY == N_HIGH_MEMORY)
>         zone_last = ZONE_MOVABLE;
> 
> Again, this is wrong, and will never be evaluated to true.
> 
> Besides removing these wrong if statements, I simplified
> the function a bit.
> 
> Signed-off-by: Oscar Salvador <osalvador@suse.de>
> Suggested-by: Pavel Tatashin <pavel.tatashin@microsoft.com>

Reviewed-by: Pavel Tatashin <pavel.tatashin@microsoft.com>

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2018-09-21 14:25 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-21 13:26 [PATCH v2 0/4] Refactor node_states_check_changes_online/offline Oscar Salvador
2018-09-21 13:26 ` [PATCH v2 1/4] mm/memory_hotplug: Spare unnecessary calls to node_set_state Oscar Salvador
2018-09-21 13:26 ` [PATCH v2 2/4] mm/memory_hotplug: Tidy up node_states_clear_node Oscar Salvador
2018-09-21 13:26 ` [PATCH v2 3/4] mm/memory_hotplug: Simplify node_states_check_changes_online Oscar Salvador
2018-09-21 14:25   ` Pasha Tatashin
2018-09-21 13:26 ` [PATCH v2 4/4] mm/memory_hotplug: Clean up node_states_check_changes_offline Oscar Salvador

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.