aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/memory.c
diff options
context:
space:
mode:
authorDavid Hildenbrand <david@redhat.com>2019-07-18 18:56:56 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-07-18 20:08:06 -0400
commitdb051a0dac13db24d58470d75cee0ce7c6b031a1 (patch)
treef245d7b2b4334de84555f6533e6af1e732aa152d /drivers/base/memory.c
parent80ec922dbd87fd38d15719c86a94457204648aeb (diff)
mm/memory_hotplug: create memory block devices after arch_add_memory()
Only memory to be added to the buddy and to be onlined/offlined by user space using /sys/devices/system/memory/... needs (and should have!) memory block devices. Factor out creation of memory block devices. Create all devices after arch_add_memory() succeeded. We can later drop the want_memblock parameter, because it is now effectively stale. Only after memory block devices have been added, memory can be onlined by user space. This implies, that memory is not visible to user space at all before arch_add_memory() succeeded. While at it - use WARN_ON_ONCE instead of BUG_ON in moved unregister_memory() - introduce find_memory_block_by_id() to search via block id - Use find_memory_block_by_id() in init_memory_block() to catch duplicates Link: http://lkml.kernel.org/r/20190527111152.16324-8-david@redhat.com Signed-off-by: David Hildenbrand <david@redhat.com> Reviewed-by: Pavel Tatashin <pasha.tatashin@soleen.com> Acked-by: Michal Hocko <mhocko@suse.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: "Rafael J. Wysocki" <rafael@kernel.org> Cc: David Hildenbrand <david@redhat.com> Cc: "mike.travis@hpe.com" <mike.travis@hpe.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Andrew Banman <andrew.banman@hpe.com> Cc: Oscar Salvador <osalvador@suse.de> Cc: Qian Cai <cai@lca.pw> Cc: Wei Yang <richard.weiyang@gmail.com> Cc: Arun KS <arunks@codeaurora.org> Cc: Mathieu Malaterre <malat@debian.org> Cc: Alex Deucher <alexander.deucher@amd.com> Cc: Andy Lutomirski <luto@kernel.org> Cc: Anshuman Khandual <anshuman.khandual@arm.com> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Baoquan He <bhe@redhat.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Chintan Pandya <cpandya@codeaurora.org> Cc: Christophe Leroy <christophe.leroy@c-s.fr> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Dan Williams <dan.j.williams@intel.com> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: "David S. Miller" <davem@davemloft.net> Cc: Fenghua Yu <fenghua.yu@intel.com> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com> Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com> Cc: Jun Yao <yaojun8558363@gmail.com> Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> Cc: Logan Gunthorpe <logang@deltatee.com> Cc: Mark Brown <broonie@kernel.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Masahiro Yamada <yamada.masahiro@socionext.com> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: Mike Rapoport <rppt@linux.vnet.ibm.com> Cc: Nicholas Piggin <npiggin@gmail.com> Cc: Oscar Salvador <osalvador@suse.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Rich Felker <dalias@libc.org> Cc: Rob Herring <robh@kernel.org> Cc: Robin Murphy <robin.murphy@arm.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Tony Luck <tony.luck@intel.com> Cc: Vasily Gorbik <gor@linux.ibm.com> Cc: Will Deacon <will.deacon@arm.com> Cc: Yoshinori Sato <ysato@users.sourceforge.jp> Cc: Yu Zhao <yuzhao@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/base/memory.c')
-rw-r--r--drivers/base/memory.c82
1 files changed, 54 insertions, 28 deletions
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 92459d6f12be..18a30c3ac0ef 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -39,6 +39,11 @@ static inline int base_memory_block_id(int section_nr)
39 return section_nr / sections_per_block; 39 return section_nr / sections_per_block;
40} 40}
41 41
42static inline int pfn_to_block_id(unsigned long pfn)
43{
44 return base_memory_block_id(pfn_to_section_nr(pfn));
45}
46
42static int memory_subsys_online(struct device *dev); 47static int memory_subsys_online(struct device *dev);
43static int memory_subsys_offline(struct device *dev); 48static int memory_subsys_offline(struct device *dev);
44 49
@@ -582,10 +587,9 @@ int __weak arch_get_memory_phys_device(unsigned long start_pfn)
582 * A reference for the returned object is held and the reference for the 587 * A reference for the returned object is held and the reference for the
583 * hinted object is released. 588 * hinted object is released.
584 */ 589 */
585struct memory_block *find_memory_block_hinted(struct mem_section *section, 590static struct memory_block *find_memory_block_by_id(int block_id,
586 struct memory_block *hint) 591 struct memory_block *hint)
587{ 592{
588 int block_id = base_memory_block_id(__section_nr(section));
589 struct device *hintdev = hint ? &hint->dev : NULL; 593 struct device *hintdev = hint ? &hint->dev : NULL;
590 struct device *dev; 594 struct device *dev;
591 595
@@ -597,6 +601,14 @@ struct memory_block *find_memory_block_hinted(struct mem_section *section,
597 return to_memory_block(dev); 601 return to_memory_block(dev);
598} 602}
599 603
604struct memory_block *find_memory_block_hinted(struct mem_section *section,
605 struct memory_block *hint)
606{
607 int block_id = base_memory_block_id(__section_nr(section));
608
609 return find_memory_block_by_id(block_id, hint);
610}
611
600/* 612/*
601 * For now, we have a linear search to go find the appropriate 613 * For now, we have a linear search to go find the appropriate
602 * memory_block corresponding to a particular phys_index. If 614 * memory_block corresponding to a particular phys_index. If
@@ -658,6 +670,11 @@ static int init_memory_block(struct memory_block **memory, int block_id,
658 unsigned long start_pfn; 670 unsigned long start_pfn;
659 int ret = 0; 671 int ret = 0;
660 672
673 mem = find_memory_block_by_id(block_id, NULL);
674 if (mem) {
675 put_device(&mem->dev);
676 return -EEXIST;
677 }
661 mem = kzalloc(sizeof(*mem), GFP_KERNEL); 678 mem = kzalloc(sizeof(*mem), GFP_KERNEL);
662 if (!mem) 679 if (!mem)
663 return -ENOMEM; 680 return -ENOMEM;
@@ -695,44 +712,53 @@ static int add_memory_block(int base_section_nr)
695 return 0; 712 return 0;
696} 713}
697 714
715static void unregister_memory(struct memory_block *memory)
716{
717 if (WARN_ON_ONCE(memory->dev.bus != &memory_subsys))
718 return;
719
720 /* drop the ref. we got via find_memory_block() */
721 put_device(&memory->dev);
722 device_unregister(&memory->dev);
723}
724
698/* 725/*
699 * need an interface for the VM to add new memory regions, 726 * Create memory block devices for the given memory area. Start and size
700 * but without onlining it. 727 * have to be aligned to memory block granularity. Memory block devices
728 * will be initialized as offline.
701 */ 729 */
702int hotplug_memory_register(int nid, struct mem_section *section) 730int create_memory_block_devices(unsigned long start, unsigned long size)
703{ 731{
704 int block_id = base_memory_block_id(__section_nr(section)); 732 const int start_block_id = pfn_to_block_id(PFN_DOWN(start));
705 int ret = 0; 733 int end_block_id = pfn_to_block_id(PFN_DOWN(start + size));
706 struct memory_block *mem; 734 struct memory_block *mem;
735 unsigned long block_id;
736 int ret = 0;
707 737
708 mutex_lock(&mem_sysfs_mutex); 738 if (WARN_ON_ONCE(!IS_ALIGNED(start, memory_block_size_bytes()) ||
739 !IS_ALIGNED(size, memory_block_size_bytes())))
740 return -EINVAL;
709 741
710 mem = find_memory_block(section); 742 mutex_lock(&mem_sysfs_mutex);
711 if (mem) { 743 for (block_id = start_block_id; block_id != end_block_id; block_id++) {
712 mem->section_count++;
713 put_device(&mem->dev);
714 } else {
715 ret = init_memory_block(&mem, block_id, MEM_OFFLINE); 744 ret = init_memory_block(&mem, block_id, MEM_OFFLINE);
716 if (ret) 745 if (ret)
717 goto out; 746 break;
718 mem->section_count++; 747 mem->section_count = sections_per_block;
748 }
749 if (ret) {
750 end_block_id = block_id;
751 for (block_id = start_block_id; block_id != end_block_id;
752 block_id++) {
753 mem = find_memory_block_by_id(block_id, NULL);
754 mem->section_count = 0;
755 unregister_memory(mem);
756 }
719 } 757 }
720
721out:
722 mutex_unlock(&mem_sysfs_mutex); 758 mutex_unlock(&mem_sysfs_mutex);
723 return ret; 759 return ret;
724} 760}
725 761
726static void
727unregister_memory(struct memory_block *memory)
728{
729 BUG_ON(memory->dev.bus != &memory_subsys);
730
731 /* drop the ref. we got via find_memory_block() */
732 put_device(&memory->dev);
733 device_unregister(&memory->dev);
734}
735
736void unregister_memory_section(struct mem_section *section) 762void unregister_memory_section(struct mem_section *section)
737{ 763{
738 struct memory_block *mem; 764 struct memory_block *mem;