[RFC PATCH 3/3] mm/memory_hotplug: Refactor shrink_zone/pgdat_span

From: osalvador
Date: Tue Aug 07 2018 - 09:38:29 EST


From: Oscar Salvador <osalvador@xxxxxxx>

This patch refactors shrink_zone_span and shrink_pgdat_span functions.

In case that find_smallest/biggest_section do not return any pfn,
it means that the zone/pgdat has no online sections left, so we can
set the respective values to 0:

zone case:
zone->zone_start_pfn = 0;
zone->spanned_pages = 0;

pgdat case:
pgdat->node_start_pfn = 0;
pgdat->node_spanned_pages = 0;

Also, the check that loops over all sections to see if we have something left
is moved to an own function, and so the code can be shared by shrink_zone_span
and shrink_pgdat_span.

Signed-off-by: Oscar Salvador <osalvador@xxxxxxx>
---
mm/memory_hotplug.c | 127 +++++++++++++++++++++++++++-------------------------
1 file changed, 65 insertions(+), 62 deletions(-)

diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index e33555651e46..ccac36eaac05 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -365,6 +365,29 @@ static unsigned long find_biggest_section_pfn(int nid, struct zone *zone,
return 0;
}

+static bool has_only_holes(struct zone *zone, int nid, unsigned long zone_start_pfn,
+ unsigned long zone_end_pfn)
+{
+ unsigned long pfn;
+
+ pfn = zone_start_pfn;
+ for (; pfn < zone_end_pfn; pfn += PAGES_PER_SECTION) {
+ struct mem_section *ms = __pfn_to_section(pfn);
+
+ if (unlikely(!online_section(ms)))
+ continue;
+ if (zone && page_zone(pfn_to_page(pfn)) != zone)
+ continue;
+
+ if (pfn_to_nid(pfn) != nid)
+ continue;
+
+ return false;
+ }
+
+ return true;
+}
+
static void shrink_zone_span(struct zone *zone, unsigned long start_pfn,
unsigned long end_pfn)
{
@@ -372,7 +395,6 @@ static void shrink_zone_span(struct zone *zone, unsigned long start_pfn,
unsigned long z = zone_end_pfn(zone); /* zone_end_pfn namespace clash */
unsigned long zone_end_pfn = z;
unsigned long pfn;
- struct mem_section *ms;
int nid = zone_to_nid(zone);

zone_span_writelock(zone);
@@ -385,10 +407,11 @@ static void shrink_zone_span(struct zone *zone, unsigned long start_pfn,
*/
pfn = find_smallest_section_pfn(nid, zone, end_pfn,
zone_end_pfn);
- if (pfn) {
- zone->zone_start_pfn = pfn;
- zone->spanned_pages = zone_end_pfn - pfn;
- }
+ if (!pfn)
+ goto only_holes;
+
+ zone->zone_start_pfn = pfn;
+ zone->spanned_pages = zone_end_pfn - pfn;
} else if (zone_end_pfn == end_pfn) {
/*
* If the section is biggest section in the zone, it need
@@ -398,38 +421,28 @@ static void shrink_zone_span(struct zone *zone, unsigned long start_pfn,
*/
pfn = find_biggest_section_pfn(nid, zone, zone_start_pfn,
start_pfn);
- if (pfn)
- zone->spanned_pages = pfn - zone_start_pfn + 1;
- }
-
- /*
- * The section is not biggest or smallest mem_section in the zone, it
- * only creates a hole in the zone. So in this case, we need not
- * change the zone. But perhaps, the zone has only hole data. Thus
- * it check the zone has only hole or not.
- */
- pfn = zone_start_pfn;
- for (; pfn < zone_end_pfn; pfn += PAGES_PER_SECTION) {
- ms = __pfn_to_section(pfn);
-
- if (unlikely(!online_section(ms)))
- continue;
+ if (!pfn)
+ goto only_holes;

- if (page_zone(pfn_to_page(pfn)) != zone)
- continue;
-
- /* If the section is current section, it continues the loop */
- if (start_pfn == pfn)
- continue;
-
- /* If we find valid section, we have nothing to do */
- zone_span_writeunlock(zone);
- return;
+ zone->spanned_pages = pfn - zone_start_pfn + 1;
+ } else {
+ /*
+ * The section is not biggest or smallest mem_section in the zone, it
+ * only creates a hole in the zone. So in this case, we need not
+ * change the zone. But perhaps, the zone has only hole data. Thus
+ * it check the zone has only hole or not.
+ */
+ if (has_only_holes(zone, nid, zone_start_pfn, zone_end_pfn))
+ goto only_holes;
}

+ goto out;
+
+only_holes:
/* The zone has no valid section */
zone->zone_start_pfn = 0;
zone->spanned_pages = 0;
+out:
zone_span_writeunlock(zone);
}

@@ -440,7 +453,6 @@ static void shrink_pgdat_span(struct pglist_data *pgdat,
unsigned long p = pgdat_end_pfn(pgdat); /* pgdat_end_pfn namespace clash */
unsigned long pgdat_end_pfn = p;
unsigned long pfn;
- struct mem_section *ms;
int nid = pgdat->node_id;

if (pgdat_start_pfn == start_pfn) {
@@ -452,10 +464,11 @@ static void shrink_pgdat_span(struct pglist_data *pgdat,
*/
pfn = find_smallest_section_pfn(nid, NULL, end_pfn,
pgdat_end_pfn);
- if (pfn) {
- pgdat->node_start_pfn = pfn;
- pgdat->node_spanned_pages = pgdat_end_pfn - pfn;
- }
+ if (!pfn)
+ goto only_holes;
+
+ pgdat->node_start_pfn = pfn;
+ pgdat->node_spanned_pages = pgdat_end_pfn - pfn;
} else if (pgdat_end_pfn == end_pfn) {
/*
* If the section is biggest section in the pgdat, it need
@@ -465,35 +478,25 @@ static void shrink_pgdat_span(struct pglist_data *pgdat,
*/
pfn = find_biggest_section_pfn(nid, NULL, pgdat_start_pfn,
start_pfn);
- if (pfn)
- pgdat->node_spanned_pages = pfn - pgdat_start_pfn + 1;
- }
-
- /*
- * If the section is not biggest or smallest mem_section in the pgdat,
- * it only creates a hole in the pgdat. So in this case, we need not
- * change the pgdat.
- * But perhaps, the pgdat has only hole data. Thus it check the pgdat
- * has only hole or not.
- */
- pfn = pgdat_start_pfn;
- for (; pfn < pgdat_end_pfn; pfn += PAGES_PER_SECTION) {
- ms = __pfn_to_section(pfn);
-
- if (unlikely(!online_section(ms)))
- continue;
-
- if (pfn_to_nid(pfn) != nid)
- continue;
+ if (!pfn)
+ goto only_holes;

- /* If the section is current section, it continues the loop */
- if (start_pfn == pfn)
- continue;
-
- /* If we find valid section, we have nothing to do */
- return;
+ pgdat->node_spanned_pages = pfn - pgdat_start_pfn + 1;
+ } else {
+ /*
+ * If the section is not biggest or smallest mem_section in the pgdat,
+ * it only creates a hole in the pgdat. So in this case, we need not
+ * change the pgdat.
+ * But perhaps, the pgdat has only hole data. Thus it check the pgdat
+ * has only hole or not.
+ */
+ if (has_only_holes(NULL, nid, pgdat_start_pfn, pgdat_end_pfn))
+ goto only_holes;
}

+ return;
+
+only_holes:
/* The pgdat has no valid section */
pgdat->node_start_pfn = 0;
pgdat->node_spanned_pages = 0;
--
2.13.6