summaryrefslogtreecommitdiffstatshomepage
path: root/mm
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2019-07-18 14:58:22 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2019-07-18 16:08:07 -0800
commit7ea6216049ff9cf250a6722cd766d99c8d1424e5 (patch)
tree404d13bb0359762c161df64effc26e10b78e3790 /mm
parent46d945aeab4d7dd837bd0724662de2caf712f047 (diff)
downloadlinux-stable-7ea6216049ff9cf250a6722cd766d99c8d1424e5.tar.gz
linux-stable-7ea6216049ff9cf250a6722cd766d99c8d1424e5.tar.bz2
linux-stable-7ea6216049ff9cf250a6722cd766d99c8d1424e5.tar.xz
linux-stable-7ea6216049ff9cf250a6722cd766d99c8d1424e5.zip
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. Link: http://lkml.kernel.org/r/156092353780.979959.9713046515562743194.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Dan Williams <dan.j.williams@intel.com> Reviewed-by: Pavel Tatashin <pasha.tatashin@soleen.com> Tested-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com> [ppc64] Reviewed-by: Oscar Salvador <osalvador@suse.de> Cc: Michal Hocko <mhocko@suse.com> Cc: Vlastimil Babka <vbabka@suse.cz> Cc: Logan Gunthorpe <logang@deltatee.com> Cc: David Hildenbrand <david@redhat.com> Cc: Jane Chu <jane.chu@oracle.com> Cc: Jeff Moyer <jmoyer@redhat.com> Cc: Jérôme Glisse <jglisse@redhat.com> Cc: Jonathan Corbet <corbet@lwn.net> Cc: Mike Rapoport <rppt@linux.ibm.com> Cc: Toshi Kani <toshi.kani@hpe.com> Cc: Wei Yang <richardw.yang@linux.intel.com> Cc: Jason Gunthorpe <jgg@mellanox.com> Cc: Christoph Hellwig <hch@lst.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/memory_hotplug.c114
-rw-r--r--mm/sparse.c16
2 files changed, 78 insertions, 52 deletions
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 11220044b01a..3fbb2cfab126 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -252,51 +252,84 @@ void __init register_page_bootmem_info_node(struct pglist_data *pgdat)
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 is 295 * Reasonably generic function for adding memory. It is
269 * expected that archs that support memory hotplug will 296 * expected that archs that support memory hotplug will
270 * call this function after deciding the zone to which to 297 * 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 request 309 * Validate altmap is within bounds of the total request
288 */ 310 */
289 if (altmap->base_pfn != phys_start_pfn 311 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 collision 335 * EEXIST is finally dealt with by ioresource collision
@@ -309,7 +342,6 @@ int __ref __add_pages(int nid, unsigned long phys_start_pfn,
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,
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)
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 zone 548 * __remove_pages() - remove sections of pages from a zone
521 * @zone: zone from which pages need to be removed 549 * @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 used 552 * @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,
528 * sure that pages are marked reserved and zones are adjust properly by 556 * 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 sections 570 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
diff --git a/mm/sparse.c b/mm/sparse.c
index 6b01022e23a9..41579b66fff1 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -728,8 +728,8 @@ static void free_map_bootmem(struct page *memmap)
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,
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,
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 */