History

mm/sparsemem: prepare for sub-section ranges

Prepare the memory hot-{add,remove} paths for handling sub-section ranges by plumbing the starting page frame and number of pages being handled through arch_{add,remove}_memory() to sparse_{add,remove}_one_section(). This is simply plumbing, small cleanups, and some identifier renames. No intended functional changes.

Dan Williams committed 7 years ago

Commit 7ea62161 parent 46d945a3 files · +81 −54Browse files

Unified · Split

3 files
  1. include/linux/memory_hotplug.h +3 −2
  2. mm/memory_hotplug.c +71 −43
  3. mm/sparse.c +7 −9
include/linux/memory_hotplug.h+3−2
@@ -346,9 +346,10 @@ extern int add_memory_resource(int nid, struct resource *resource); · 345 unmodified lines
346extern void move_pfn_range_to_zone(struct zone *zone, unsigned long start_pfn,346extern void move_pfn_range_to_zone(struct zone *zone, unsigned long start_pfn,
347 unsigned long nr_pages, struct vmem_altmap *altmap);347 unsigned long nr_pages, struct vmem_altmap *altmap);
348extern bool is_memblock_offlined(struct memory_block *mem);348extern bool is_memblock_offlined(struct memory_block *mem);
349extern int sparse_add_one_section(int nid, unsigned long start_pfn,349extern int sparse_add_section(int nid, unsigned long pfn,
350 struct vmem_altmap *altmap);350 unsigned long nr_pages, struct vmem_altmap *altmap);
351extern void sparse_remove_one_section(struct mem_section *ms,351extern void sparse_remove_one_section(struct mem_section *ms,
352 unsigned long pfn, unsigned long nr_pages,
352 unsigned long map_offset, struct vmem_altmap *altmap);353 unsigned long map_offset, struct vmem_altmap *altmap);
353extern struct page *sparse_decode_mem_map(unsigned long coded_mem_map,354extern struct page *sparse_decode_mem_map(unsigned long coded_mem_map,
354 unsigned long pnum);355 unsigned long pnum);
mm/memory_hotplug.c+71−43
@@ -252,51 +252,84 @@ void __init register_page_bootmem_info_node(struct pglist_data *pgdat) · 251 unmodified lines
252}252}
253#endif /* CONFIG_HAVE_BOOTMEM_INFO_NODE */253#endif /* CONFIG_HAVE_BOOTMEM_INFO_NODE */
254 254
255static int __meminit __add_section(int nid, unsigned long phys_start_pfn,255static int __meminit __add_section(int nid, unsigned long pfn,
256 struct vmem_altmap *altmap)256 unsigned long nr_pages, struct vmem_altmap *altmap)
257{257{
258 int ret;258 int ret;
259 259
260 if (pfn_valid(phys_start_pfn))260 if (pfn_valid(pfn))
261 return -EEXIST;261 return -EEXIST;
262 262
263 ret = sparse_add_one_section(nid, phys_start_pfn, altmap);263 ret = sparse_add_section(nid, pfn, nr_pages, altmap);
264 return ret < 0 ? ret : 0;264 return ret < 0 ? ret : 0;
265}265}
266 266
267static int check_pfn_span(unsigned long pfn, unsigned long nr_pages,
268 const char *reason)
269{
270 /*
271 * Disallow all operations smaller than a sub-section and only
272 * allow operations smaller than a section for
273 * SPARSEMEM_VMEMMAP. Note that check_hotplug_memory_range()
274 * enforces a larger memory_block_size_bytes() granularity for
275 * memory that will be marked online, so this check should only
276 * fire for direct arch_{add,remove}_memory() users outside of
277 * add_memory_resource().
278 */
279 unsigned long min_align;
280
281 if (IS_ENABLED(CONFIG_SPARSEMEM_VMEMMAP))
282 min_align = PAGES_PER_SUBSECTION;
283 else
284 min_align = PAGES_PER_SECTION;
285 if (!IS_ALIGNED(pfn, min_align)
286 || !IS_ALIGNED(nr_pages, min_align)) {
287 WARN(1, "Misaligned __%s_pages start: %#lx end: #%lx\n",
288 reason, pfn, pfn + nr_pages - 1);
289 return -EINVAL;
290 }
291 return 0;
292}
293
267/*294/*
268 * Reasonably generic function for adding memory. It is295 * Reasonably generic function for adding memory. It is
269 * expected that archs that support memory hotplug will296 * expected that archs that support memory hotplug will
270 * call this function after deciding the zone to which to297 * call this function after deciding the zone to which to
271 * add the new pages.298 * add the new pages.
272 */299 */
273int __ref __add_pages(int nid, unsigned long phys_start_pfn,300int __ref __add_pages(int nid, unsigned long pfn, unsigned long nr_pages,
274 unsigned long nr_pages, struct mhp_restrictions *restrictions)301 struct mhp_restrictions *restrictions)
275{302{
276 unsigned long i;303 unsigned long i;
277 int err = 0;304 int start_sec, end_sec, err;
278 int start_sec, end_sec;
279 struct vmem_altmap *altmap = restrictions->altmap;305 struct vmem_altmap *altmap = restrictions->altmap;
280 306
281 /* during initialize mem_map, align hot-added range to section */
282 start_sec = pfn_to_section_nr(phys_start_pfn);
283 end_sec = pfn_to_section_nr(phys_start_pfn + nr_pages - 1);
284
285 if (altmap) {307 if (altmap) {
286 /*308 /*
287 * Validate altmap is within bounds of the total request309 * Validate altmap is within bounds of the total request
288 */310 */
289 if (altmap->base_pfn != phys_start_pfn311 if (altmap->base_pfn != pfn
290 || vmem_altmap_offset(altmap) > nr_pages) {312 || vmem_altmap_offset(altmap) > nr_pages) {
291 pr_warn_once("memory add fail, invalid altmap\n");313 pr_warn_once("memory add fail, invalid altmap\n");
292 err = -EINVAL;314 return -EINVAL;
293 goto out;
294 }315 }
295 altmap->alloc = 0;316 altmap->alloc = 0;
296 }317 }
297 318
319 err = check_pfn_span(pfn, nr_pages, "add");
320 if (err)
321 return err;
322
323 start_sec = pfn_to_section_nr(pfn);
324 end_sec = pfn_to_section_nr(pfn + nr_pages - 1);
298 for (i = start_sec; i <= end_sec; i++) {325 for (i = start_sec; i <= end_sec; i++) {
299 err = __add_section(nid, section_nr_to_pfn(i), altmap);326 unsigned long pfns;
327
328 pfns = min(nr_pages, PAGES_PER_SECTION
329 - (pfn & ~PAGE_SECTION_MASK));
330 err = __add_section(nid, pfn, pfns, altmap);
331 pfn += pfns;
332 nr_pages -= pfns;
300 333
301 /*334 /*
302 * EEXIST is finally dealt with by ioresource collision335 * EEXIST is finally dealt with by ioresource collision
@@ -309,7 +342,6 @@ int __ref __add_pages(int nid, unsigned long phys_start_pfn, · 6 unmodified lines
309 cond_resched();342 cond_resched();
310 }343 }
311 vmemmap_populate_print_last();344 vmemmap_populate_print_last();
312out:
313 return err;345 return err;
314}346}
315 347
@@ -487,10 +519,10 @@ static void shrink_pgdat_span(struct pglist_data *pgdat, · 171 unmodified lines
487 pgdat->node_spanned_pages = 0;519 pgdat->node_spanned_pages = 0;
488}520}
489 521
490static void __remove_zone(struct zone *zone, unsigned long start_pfn)522static void __remove_zone(struct zone *zone, unsigned long start_pfn,
523 unsigned long nr_pages)
491{524{
492 struct pglist_data *pgdat = zone->zone_pgdat;525 struct pglist_data *pgdat = zone->zone_pgdat;
493 int nr_pages = PAGES_PER_SECTION;
494 unsigned long flags;526 unsigned long flags;
495 527
496 pgdat_resize_lock(zone->zone_pgdat, &flags);528 pgdat_resize_lock(zone->zone_pgdat, &flags);
@@ -499,27 +531,23 @@ static void __remove_zone(struct zone *zone, unsigned long start_pfn) · 2 unmodified lines
499 pgdat_resize_unlock(zone->zone_pgdat, &flags);531 pgdat_resize_unlock(zone->zone_pgdat, &flags);
500}532}
501 533
502static void __remove_section(struct zone *zone, struct mem_section *ms,534static void __remove_section(struct zone *zone, unsigned long pfn,
503 unsigned long map_offset,535 unsigned long nr_pages, unsigned long map_offset,
504 struct vmem_altmap *altmap)536 struct vmem_altmap *altmap)
505{537{
506 unsigned long start_pfn;538 struct mem_section *ms = __nr_to_section(pfn_to_section_nr(pfn));
507 int scn_nr;
508 539
509 if (WARN_ON_ONCE(!valid_section(ms)))540 if (WARN_ON_ONCE(!valid_section(ms)))
510 return;541 return;
511 542
512 scn_nr = __section_nr(ms);543 __remove_zone(zone, pfn, nr_pages);
513 start_pfn = section_nr_to_pfn((unsigned long)scn_nr);544 sparse_remove_one_section(ms, pfn, nr_pages, map_offset, altmap);
514 __remove_zone(zone, start_pfn);
515
516 sparse_remove_one_section(ms, map_offset, altmap);
517}545}
518 546
519/**547/**
520 * __remove_pages() - remove sections of pages from a zone548 * __remove_pages() - remove sections of pages from a zone
521 * @zone: zone from which pages need to be removed549 * @zone: zone from which pages need to be removed
522 * @phys_start_pfn: starting pageframe (must be aligned to start of a section)550 * @pfn: starting pageframe (must be aligned to start of a section)
523 * @nr_pages: number of pages to remove (must be multiple of section size)551 * @nr_pages: number of pages to remove (must be multiple of section size)
524 * @altmap: alternative device page map or %NULL if default memmap is used552 * @altmap: alternative device page map or %NULL if default memmap is used
525 *553 *
@@ -528,30 +556,30 @@ static void __remove_section(struct zone *zone, struct mem_section *ms, · 2 unmodified lines
528 * sure that pages are marked reserved and zones are adjust properly by556 * sure that pages are marked reserved and zones are adjust properly by
529 * calling offline_pages().557 * calling offline_pages().
530 */558 */
531void __remove_pages(struct zone *zone, unsigned long phys_start_pfn,559void __remove_pages(struct zone *zone, unsigned long pfn,
532 unsigned long nr_pages, struct vmem_altmap *altmap)560 unsigned long nr_pages, struct vmem_altmap *altmap)
533{561{
534 unsigned long i;
535 unsigned long map_offset = 0;562 unsigned long map_offset = 0;
536 int sections_to_remove;563 int i, start_sec, end_sec;
537 564
538 map_offset = vmem_altmap_offset(altmap);565 map_offset = vmem_altmap_offset(altmap);
539 566
540 clear_zone_contiguous(zone);567 clear_zone_contiguous(zone);
541 568
542 /*569 if (check_pfn_span(pfn, nr_pages, "remove"))
543 * We can only remove entire sections570 return;
544 */
545 BUG_ON(phys_start_pfn & ~PAGE_SECTION_MASK);
546 BUG_ON(nr_pages % PAGES_PER_SECTION);
547 571
548 sections_to_remove = nr_pages / PAGES_PER_SECTION;572 start_sec = pfn_to_section_nr(pfn);
549 for (i = 0; i < sections_to_remove; i++) {573 end_sec = pfn_to_section_nr(pfn + nr_pages - 1);
550 unsigned long pfn = phys_start_pfn + i*PAGES_PER_SECTION;574 for (i = start_sec; i <= end_sec; i++) {
575 unsigned long pfns;
551 576
552 cond_resched();577 cond_resched();
553 __remove_section(zone, __pfn_to_section(pfn), map_offset,578 pfns = min(nr_pages, PAGES_PER_SECTION
554 altmap);579 - (pfn & ~PAGE_SECTION_MASK));
580 __remove_section(zone, pfn, pfns, map_offset, altmap);
581 pfn += pfns;
582 nr_pages -= pfns;
555 map_offset = 0;583 map_offset = 0;
556 }584 }
557 585
mm/sparse.c+7−9
@@ -728,8 +728,8 @@ static void free_map_bootmem(struct page *memmap) · 727 unmodified lines
728 * * -EEXIST - Section has been present.728 * * -EEXIST - Section has been present.
729 * * -ENOMEM - Out of memory.729 * * -ENOMEM - Out of memory.
730 */730 */
731int __meminit sparse_add_one_section(int nid, unsigned long start_pfn,731int __meminit sparse_add_section(int nid, unsigned long start_pfn,
732 struct vmem_altmap *altmap)732 unsigned long nr_pages, struct vmem_altmap *altmap)
733{733{
734 unsigned long section_nr = pfn_to_section_nr(start_pfn);734 unsigned long section_nr = pfn_to_section_nr(start_pfn);
735 struct mem_section_usage *usage;735 struct mem_section_usage *usage;
@@ -835,8 +835,9 @@ static void free_section_usage(struct mem_section *ms, struct page *memmap, · 99 unmodified lines
835 free_map_bootmem(memmap);835 free_map_bootmem(memmap);
836}836}
837 837
838void sparse_remove_one_section(struct mem_section *ms, unsigned long map_offset,838void sparse_remove_one_section(struct mem_section *ms, unsigned long pfn,
839 struct vmem_altmap *altmap)839 unsigned long nr_pages, unsigned long map_offset,
840 struct vmem_altmap *altmap)
840{841{
841 struct page *memmap = NULL;842 struct page *memmap = NULL;
842 struct mem_section_usage *usage = NULL;843 struct mem_section_usage *usage = NULL;
@@ -849,10 +850,7 @@ void sparse_remove_one_section(struct mem_section *ms, unsigned long map_offset, · 6 unmodified lines
849 ms->usage = NULL;850 ms->usage = NULL;
850 }851 }
851 852
852 clear_hwpoisoned_pages(memmap + map_offset,853 clear_hwpoisoned_pages(memmap + map_offset, nr_pages - map_offset);
853 PAGES_PER_SECTION - map_offset);854 free_section_usage(ms, memmap, usage, pfn, nr_pages, altmap);
854 free_section_usage(ms, memmap, usage,
855 section_nr_to_pfn(__section_nr(ms)),
856 PAGES_PER_SECTION, altmap);
857}855}
858#endif /* CONFIG_MEMORY_HOTPLUG */856#endif /* CONFIG_MEMORY_HOTPLUG */