LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: memory-hotplug : suppres "Trying to free nonexistent resource <XXXXXXXXXXXXXXXX-YYYYYYYYYYYYYYYY>" warning
From: Andrew Morton @ 2012-10-05 21:09 UTC (permalink / raw)
  To: Yasuaki Ishimatsu
  Cc: len.brown, wency, linux-acpi, x86, linux-kernel, linux-mm, paulus,
	minchan.kim, kosaki.motohiro, rientjes, cl, linuxppc-dev, liuj97
In-Reply-To: <506D1F1D.9000301@jp.fujitsu.com>

On Thu, 4 Oct 2012 14:31:09 +0900
Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com> wrote:

> When our x86 box calls __remove_pages(), release_mem_region() shows
> many warnings. And x86 box cannot unregister iomem_resource.
> 
> "Trying to free nonexistent resource <XXXXXXXXXXXXXXXX-YYYYYYYYYYYYYYYY>"
> 
> release_mem_region() has been changed as called in each PAGES_PER_SECTION
> chunk since applying a patch(de7f0cba96786c). Because powerpc registers
> iomem_resource in each PAGES_PER_SECTION chunk. But when I hot add memory
> on x86 box, iomem_resource is register in each _CRS not PAGES_PER_SECTION
> chunk. So x86 box unregisters iomem_resource.
> 
> The patch fixes the problem.
> 
> --- linux-3.6.orig/arch/powerpc/platforms/pseries/hotplug-memory.c	2012-10-04 14:22:59.833520792 +0900
> +++ linux-3.6/arch/powerpc/platforms/pseries/hotplug-memory.c	2012-10-04 14:23:05.150521411 +0900
> @@ -77,7 +77,8 @@ static int pseries_remove_memblock(unsig
>  {
>  	unsigned long start, start_pfn;
>  	struct zone *zone;
> -	int ret;
> +	int i, ret;
> +	int sections_to_remove;
>  
>  	start_pfn = base >> PAGE_SHIFT;
>  
> @@ -97,9 +98,13 @@ static int pseries_remove_memblock(unsig
>  	 * to sysfs "state" file and we can't remove sysfs entries
>  	 * while writing to it. So we have to defer it to here.
>  	 */
> -	ret = __remove_pages(zone, start_pfn, memblock_size >> PAGE_SHIFT);
> -	if (ret)
> -		return ret;
> +	sections_to_remove = (memblock_size >> PAGE_SHIFT) / PAGES_PER_SECTION;
> +	for (i = 0; i < sections_to_remove; i++) {
> +		unsigned long pfn = start_pfn + i * PAGES_PER_SECTION;
> +		ret = __remove_pages(zone, start_pfn,  PAGES_PER_SECTION);
> +		if (ret)
> +			return ret;
> +	}

It is inappropriate that `i' have a signed 32-bit type.  I doubt if
there's any possibility of an overflow bug here, but using a consistent
and well-chosen type would eliminate all doubt.

Note that __remove_pages() does use an unsigned long for this, although
it stupidly calls that variable "i", despite the C programmers'
expectation that a variable called "i" has type "int".

The same applies to `sections_to_remove', but __remove_pages() went and
decided to use an `int' for that variable.  Sigh.

Anyway, please have a think, and see if we can come up with the best
and most accurate choice of types and identifiers in this code.

^ permalink raw reply

* [PATCH] powerpc/mpc5200: move lpbfifo node and fix its interrupt property
From: Anatolij Gustschin @ 2012-10-05 20:23 UTC (permalink / raw)
  To: linuxppc-dev

The LPB FIFO interrupt is a peripheral interrupt, thus its L1 cell
has to be 2 instead of 3. Fix it and while at it, move the lpbfifo
node to the common dtsi file.

Reported-by: Stefan Roese <sr@denx.de>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
---
 arch/powerpc/boot/dts/mpc5200b.dtsi |    6 ++++++
 arch/powerpc/boot/dts/o2d.dtsi      |    6 ------
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc5200b.dtsi b/arch/powerpc/boot/dts/mpc5200b.dtsi
index 7ab286a..39ed65a 100644
--- a/arch/powerpc/boot/dts/mpc5200b.dtsi
+++ b/arch/powerpc/boot/dts/mpc5200b.dtsi
@@ -231,6 +231,12 @@
 			interrupts = <2 7 0>;
 		};
 
+		sclpc@3c00 {
+			compatible = "fsl,mpc5200-lpbfifo";
+			reg = <0x3c00 0x60>;
+			interrupts = <2 23 0>;
+		};
+
 		i2c@3d00 {
 			#address-cells = <1>;
 			#size-cells = <0>;
diff --git a/arch/powerpc/boot/dts/o2d.dtsi b/arch/powerpc/boot/dts/o2d.dtsi
index 3444eb8..24f6680 100644
--- a/arch/powerpc/boot/dts/o2d.dtsi
+++ b/arch/powerpc/boot/dts/o2d.dtsi
@@ -86,12 +86,6 @@
 				reg = <0>;
 			};
 		};
-
-		sclpc@3c00 {
-			compatible = "fsl,mpc5200-lpbfifo";
-			reg = <0x3c00 0x60>;
-			interrupts = <3 23 0>;
-		};
 	};
 
 	localbus {
-- 
1.7.5.4

^ permalink raw reply related

* Re: [PATCH 2/10] memory-hotplug : remove /sys/firmware/memmap/X sysfs
From: KOSAKI Motohiro @ 2012-10-05 19:36 UTC (permalink / raw)
  To: Yasuaki Ishimatsu
  Cc: linux-s390, linux-ia64, wency, len.brown, linux-acpi, linux-sh,
	x86, linux-kernel, cmetcalf, linux-mm, minchan.kim, rientjes,
	sparclinux, cl, linuxppc-dev, akpm, liuj97
In-Reply-To: <506E4571.4090608@jp.fujitsu.com>

On Thu, Oct 4, 2012 at 10:26 PM, Yasuaki Ishimatsu
<isimatu.yasuaki@jp.fujitsu.com> wrote:
> When (hot)adding memory into system, /sys/firmware/memmap/X/{end, start, type}
> sysfs files are created. But there is no code to remove these files. The patch
> implements the function to remove them.
>
> Note : The code does not free firmware_map_entry since there is no way to free
>        memory which is allocated by bootmem.

You have to explain why this is ok. I guess the unfreed
firmware_map_entry is reused
at next online memory and don't make memory leak, right?



>
> CC: David Rientjes <rientjes@google.com>
> CC: Jiang Liu <liuj97@gmail.com>
> CC: Len Brown <len.brown@intel.com>
> CC: Christoph Lameter <cl@linux.com>
> Cc: Minchan Kim <minchan.kim@gmail.com>
> CC: Andrew Morton <akpm@linux-foundation.org>
> CC: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
> Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
> Signed-off-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
>
> ---
>  drivers/firmware/memmap.c    |   98 ++++++++++++++++++++++++++++++++++++++++++-
>  include/linux/firmware-map.h |    6 ++
>  mm/memory_hotplug.c          |    7 ++-
>  3 files changed, 108 insertions(+), 3 deletions(-)
>
> Index: linux-3.6/drivers/firmware/memmap.c
> ===================================================================
> --- linux-3.6.orig/drivers/firmware/memmap.c    2012-10-04 18:27:05.195500420 +0900
> +++ linux-3.6/drivers/firmware/memmap.c 2012-10-04 18:27:18.901514330 +0900
> @@ -21,6 +21,7 @@
>  #include <linux/types.h>
>  #include <linux/bootmem.h>
>  #include <linux/slab.h>
> +#include <linux/mm.h>
>
>  /*
>   * Data types ------------------------------------------------------------------
> @@ -41,6 +42,7 @@ struct firmware_map_entry {
>         const char              *type;  /* type of the memory range */
>         struct list_head        list;   /* entry for the linked list */
>         struct kobject          kobj;   /* kobject for each entry */
> +       unsigned int            bootmem:1; /* allocated from bootmem */

Use bool.


>  };
>
>  /*
> @@ -79,7 +81,26 @@ static const struct sysfs_ops memmap_att
>         .show = memmap_attr_show,
>  };
>
> +
> +static inline struct firmware_map_entry *
> +to_memmap_entry(struct kobject *kobj)
> +{
> +       return container_of(kobj, struct firmware_map_entry, kobj);
> +}
> +
> +static void release_firmware_map_entry(struct kobject *kobj)
> +{
> +       struct firmware_map_entry *entry = to_memmap_entry(kobj);
> +
> +       if (entry->bootmem)
> +               /* There is no way to free memory allocated from bootmem */
> +               return;
> +
> +       kfree(entry);
> +}
> +
>  static struct kobj_type memmap_ktype = {
> +       .release        = release_firmware_map_entry,
>         .sysfs_ops      = &memmap_attr_ops,
>         .default_attrs  = def_attrs,
>  };
> @@ -94,6 +115,7 @@ static struct kobj_type memmap_ktype = {
>   * in firmware initialisation code in one single thread of execution.
>   */
>  static LIST_HEAD(map_entries);
> +static DEFINE_SPINLOCK(map_entries_lock);
>
>  /**
>   * firmware_map_add_entry() - Does the real work to add a firmware memmap entry.
> @@ -118,11 +140,25 @@ static int firmware_map_add_entry(u64 st
>         INIT_LIST_HEAD(&entry->list);
>         kobject_init(&entry->kobj, &memmap_ktype);
>
> +       spin_lock(&map_entries_lock);
>         list_add_tail(&entry->list, &map_entries);
> +       spin_unlock(&map_entries_lock);
>
>         return 0;
>  }
>
> +/**
> + * firmware_map_remove_entry() - Does the real work to remove a firmware
> + * memmap entry.
> + * @entry: removed entry.
> + **/
> +static inline void firmware_map_remove_entry(struct firmware_map_entry *entry)

Don't use inline in *.c file. gcc is wise than you.

> +{
> +       spin_lock(&map_entries_lock);
> +       list_del(&entry->list);
> +       spin_unlock(&map_entries_lock);
> +}
> +
>  /*
>   * Add memmap entry on sysfs
>   */
> @@ -144,6 +180,35 @@ static int add_sysfs_fw_map_entry(struct
>         return 0;
>  }
>
> +/*
> + * Remove memmap entry on sysfs
> + */
> +static inline void remove_sysfs_fw_map_entry(struct firmware_map_entry *entry)
> +{
> +       kobject_put(&entry->kobj);
> +}
> +
> +/*
> + * Search memmap entry
> + */
> +
> +static struct firmware_map_entry * __meminit
> +firmware_map_find_entry(u64 start, u64 end, const char *type)
> +{
> +       struct firmware_map_entry *entry;
> +
> +       spin_lock(&map_entries_lock);
> +       list_for_each_entry(entry, &map_entries, list)
> +               if ((entry->start == start) && (entry->end == end) &&
> +                   (!strcmp(entry->type, type))) {
> +                       spin_unlock(&map_entries_lock);
> +                       return entry;
> +               }
> +
> +       spin_unlock(&map_entries_lock);
> +       return NULL;
> +}
> +
>  /**
>   * firmware_map_add_hotplug() - Adds a firmware mapping entry when we do
>   * memory hotplug.
> @@ -193,9 +258,36 @@ int __init firmware_map_add_early(u64 st
>         if (WARN_ON(!entry))
>                 return -ENOMEM;
>
> +       entry->bootmem = 1;
>         return firmware_map_add_entry(start, end, type, entry);
>  }
>
> +/**
> + * firmware_map_remove() - remove a firmware mapping entry
> + * @start: Start of the memory range.
> + * @end:   End of the memory range.
> + * @type:  Type of the memory range.
> + *
> + * removes a firmware mapping entry.
> + *
> + * Returns 0 on success, or -EINVAL if no entry.
> + **/
> +int __meminit firmware_map_remove(u64 start, u64 end, const char *type)

Remove type argument if this is always passed "System RAM".

> +{
> +       struct firmware_map_entry *entry;
> +
> +       entry = firmware_map_find_entry(start, end - 1, type);
> +       if (!entry)
> +               return -EINVAL;
> +
> +       firmware_map_remove_entry(entry);
> +
> +       /* remove the memmap entry */
> +       remove_sysfs_fw_map_entry(entry);
> +
> +       return 0;
> +}
> +
>  /*
>   * Sysfs functions -------------------------------------------------------------
>   */
> @@ -217,8 +309,10 @@ static ssize_t type_show(struct firmware
>         return snprintf(buf, PAGE_SIZE, "%s\n", entry->type);
>  }
>
> -#define to_memmap_attr(_attr) container_of(_attr, struct memmap_attribute, attr)
> -#define to_memmap_entry(obj) container_of(obj, struct firmware_map_entry, kobj)
> +static inline struct memmap_attribute *to_memmap_attr(struct attribute *attr)
> +{
> +       return container_of(attr, struct memmap_attribute, attr);
> +}
>
>  static ssize_t memmap_attr_show(struct kobject *kobj,
>                                 struct attribute *attr, char *buf)
> Index: linux-3.6/include/linux/firmware-map.h
> ===================================================================
> --- linux-3.6.orig/include/linux/firmware-map.h 2012-10-04 18:27:05.197500422 +0900
> +++ linux-3.6/include/linux/firmware-map.h      2012-10-04 18:27:18.904514333 +0900
> @@ -25,6 +25,7 @@
>
>  int firmware_map_add_early(u64 start, u64 end, const char *type);
>  int firmware_map_add_hotplug(u64 start, u64 end, const char *type);
> +int firmware_map_remove(u64 start, u64 end, const char *type);
>
>  #else /* CONFIG_FIRMWARE_MEMMAP */
>
> @@ -38,6 +39,11 @@ static inline int firmware_map_add_hotpl
>         return 0;
>  }
>
> +static inline int firmware_map_remove(u64 start, u64 end, const char *type)
> +{
> +       return 0;
> +}
> +
>  #endif /* CONFIG_FIRMWARE_MEMMAP */
>
>  #endif /* _LINUX_FIRMWARE_MAP_H */
> Index: linux-3.6/mm/memory_hotplug.c
> ===================================================================
> --- linux-3.6.orig/mm/memory_hotplug.c  2012-10-04 18:27:03.000000000 +0900
> +++ linux-3.6/mm/memory_hotplug.c       2012-10-04 18:28:42.851599524 +0900
> @@ -1043,7 +1043,7 @@ int offline_memory(u64 start, u64 size)
>         return 0;
>  }
>
> -int remove_memory(int nid, u64 start, u64 size)
> +int __ref remove_memory(int nid, u64 start, u64 size)
>  {
>         int ret = 0;
>         lock_memory_hotplug();
> @@ -1056,8 +1056,13 @@ int remove_memory(int nid, u64 start, u6
>                         "because the memmory range is online\n",
>                         start, start + size);
>                 ret = -EAGAIN;
> +               goto out;
>         }
>
> +       /* remove memmap entry */
> +       firmware_map_remove(start, start + size, "System RAM");
> +
> +out:
>         unlock_memory_hotplug();
>         return ret;
>  }


Other than that, looks ok to me.

^ permalink raw reply

* Re: [PATCH 1/10] memory-hotplug : check whether memory is offline or not when removing memory
From: KOSAKI Motohiro @ 2012-10-05 19:27 UTC (permalink / raw)
  To: Yasuaki Ishimatsu
  Cc: linux-s390, linux-ia64, wency, len.brown, linux-acpi, linux-sh,
	x86, linux-kernel, cmetcalf, linux-mm, minchan.kim, rientjes,
	sparclinux, cl, linuxppc-dev, akpm, liuj97
In-Reply-To: <506E451E.1050403@jp.fujitsu.com>

On Thu, Oct 4, 2012 at 10:25 PM, Yasuaki Ishimatsu
<isimatu.yasuaki@jp.fujitsu.com> wrote:
> When calling remove_memory(), the memory should be offline. If the function
> is used to online memory, kernel panic may occur.
>
> So the patch checks whether memory is offline or not.

You don't explain WHY we need the check.


> CC: David Rientjes <rientjes@google.com>
> CC: Jiang Liu <liuj97@gmail.com>
> CC: Len Brown <len.brown@intel.com>
> CC: Christoph Lameter <cl@linux.com>
> Cc: Minchan Kim <minchan.kim@gmail.com>
> CC: Andrew Morton <akpm@linux-foundation.org>
> CC: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
> Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
> Signed-off-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
>
> ---
>  drivers/base/memory.c  |   39 +++++++++++++++++++++++++++++++++++++++
>  include/linux/memory.h |    5 +++++
>  mm/memory_hotplug.c    |   17 +++++++++++++++--
>  3 files changed, 59 insertions(+), 2 deletions(-)
>
> Index: linux-3.6/drivers/base/memory.c
> ===================================================================
> --- linux-3.6.orig/drivers/base/memory.c        2012-10-04 14:22:57.000000000 +0900
> +++ linux-3.6/drivers/base/memory.c     2012-10-04 14:45:46.653585860 +0900
> @@ -70,6 +70,45 @@ void unregister_memory_isolate_notifier(
>  }
>  EXPORT_SYMBOL(unregister_memory_isolate_notifier);
>
> +bool is_memblk_offline(unsigned long start, unsigned long size)

Don't use memblk. Usually memblk mean struct numa_meminfo for x86/numa.
Maybe memory_range_offlined() is better.

And, this function don't take struct memory_block, then this file may be no good
place.

And you need to write down function comment.


> +{
> +       struct memory_block *mem = NULL;
> +       struct mem_section *section;
> +       unsigned long start_pfn, end_pfn;
> +       unsigned long pfn, section_nr;
> +
> +       start_pfn = PFN_DOWN(start);
> +       end_pfn = PFN_UP(start + size);
> +
> +       for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
> +               section_nr = pfn_to_section_nr(pfn);
> +               if (!present_section_nr(section_nr))
> +                       continue;
> +
> +               section = __nr_to_section(section_nr);
> +               /* same memblock? */
> +               if (mem)
> +                       if ((section_nr >= mem->start_section_nr) &&
> +                           (section_nr <= mem->end_section_nr))
> +                               continue;
> +
> +               mem = find_memory_block_hinted(section, mem);
> +               if (!mem)
> +                       continue;
> +               if (mem->state == MEM_OFFLINE)
> +                       continue;
> +
> +               kobject_put(&mem->dev.kobj);
> +               return false;
> +       }
> +
> +       if (mem)
> +               kobject_put(&mem->dev.kobj);
> +
> +       return true;
> +}
> +EXPORT_SYMBOL(is_memblk_offline);
> +
>  /*
>   * register_memory - Setup a sysfs device for a memory block
>   */
> Index: linux-3.6/include/linux/memory.h
> ===================================================================
> --- linux-3.6.orig/include/linux/memory.h       2012-10-02 18:00:22.000000000 +0900
> +++ linux-3.6/include/linux/memory.h    2012-10-04 14:44:40.902581028 +0900
> @@ -106,6 +106,10 @@ static inline int memory_isolate_notify(
>  {
>         return 0;
>  }
> +static inline bool is_memblk_offline(unsigned long start, unsigned long size)
> +{
> +       return false;
> +}
>  #else
>  extern int register_memory_notifier(struct notifier_block *nb);
>  extern void unregister_memory_notifier(struct notifier_block *nb);
> @@ -120,6 +124,7 @@ extern int memory_isolate_notify(unsigne
>  extern struct memory_block *find_memory_block_hinted(struct mem_section *,
>                                                         struct memory_block *);
>  extern struct memory_block *find_memory_block(struct mem_section *);
> +extern bool is_memblk_offline(unsigned long start, unsigned long size);
>  #define CONFIG_MEM_BLOCK_SIZE  (PAGES_PER_SECTION<<PAGE_SHIFT)
>  enum mem_add_context { BOOT, HOTPLUG };
>  #endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
> Index: linux-3.6/mm/memory_hotplug.c
> ===================================================================
> --- linux-3.6.orig/mm/memory_hotplug.c  2012-10-04 14:31:08.000000000 +0900
> +++ linux-3.6/mm/memory_hotplug.c       2012-10-04 14:58:22.449687986 +0900
> @@ -1045,8 +1045,21 @@ int offline_memory(u64 start, u64 size)
>
>  int remove_memory(int nid, u64 start, u64 size)
>  {

Your remove_memory() don't remove anything. that's strange.


> -       /* It is not implemented yet*/
> -       return 0;
> +       int ret = 0;
> +       lock_memory_hotplug();
> +       /*
> +        * The memory might become online by other task, even if you offine it.
> +        * So we check whether the memory has been onlined or not.
> +        */
> +       if (!is_memblk_offline(start, size)) {
> +               pr_warn("memory removing [mem %#010llx-%#010llx] failed, "
> +                       "because the memmory range is online\n",
> +                       start, start + size);

No good warning. You should output which memory block can't be
offlined, I think.


> +               ret = -EAGAIN;
> +       }
> +
> +       unlock_memory_hotplug();
> +       return ret;
>  }
>  EXPORT_SYMBOL_GPL(remove_memory);
>  #else
>
> --
> To unsubscribe, send a message with 'unsubscribe linux-mm' in
> the body to majordomo@kvack.org.  For more info on Linux MM,
> see: http://www.linux-mm.org/ .
> Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply

* Re: [PATCH 0/10] memory-hotplug: hot-remove physical memory
From: KOSAKI Motohiro @ 2012-10-05 19:06 UTC (permalink / raw)
  To: Yasuaki Ishimatsu
  Cc: linux-s390, linux-ia64, wency, len.brown, linux-acpi, linux-sh,
	x86, linux-kernel, cmetcalf, linux-mm, minchan.kim, rientjes,
	sparclinux, cl, linuxppc-dev, akpm, liuj97
In-Reply-To: <506E43E0.70507@jp.fujitsu.com>

> Known problems:
> 1. memory can't be offlined when CONFIG_MEMCG is selected.
>    For example: there is a memory device on node 1. The address range
>    is [1G, 1.5G). You will find 4 new directories memory8, memory9, memory10,
>    and memory11 under the directory /sys/devices/system/memory/.
>    If CONFIG_MEMCG is selected, we will allocate memory to store page cgroup
>    when we online pages. When we online memory8, the memory stored page cgroup
>    is not provided by this memory device. But when we online memory9, the memory
>    stored page cgroup may be provided by memory8. So we can't offline memory8
>    now. We should offline the memory in the reversed order.
>    When the memory device is hotremoved, we will auto offline memory provided
>    by this memory device. But we don't know which memory is onlined first, so
>    offlining memory may fail. In such case, you should offline the memory by
>    hand before hotremoving the memory device.

Just iterate twice. 1st iterate: offline every non primary memory
block. 2nd iterate:
offline primary (i.e. first added) memory block. It may work.

^ permalink raw reply

* Re: memory-hotplug : suppres "Trying to free nonexistent resource <XXXXXXXXXXXXXXXX-YYYYYYYYYYYYYYYY>" warning
From: KOSAKI Motohiro @ 2012-10-05 19:01 UTC (permalink / raw)
  To: Yasuaki Ishimatsu
  Cc: len.brown, wency, linux-acpi, x86, linux-kernel, Dave Hansen,
	linux-mm, paulus, minchan.kim, rientjes, cl, linuxppc-dev, akpm,
	liuj97
In-Reply-To: <506D1F1D.9000301@jp.fujitsu.com>

CC to Dave Hanse.

Hello Dave,

I think following patch works both x86 and ppc. but I'm not ppc
expert. So I'm glad
if you double check it.

thank you.


<intentional full quote>

> When our x86 box calls __remove_pages(), release_mem_region() shows
> many warnings. And x86 box cannot unregister iomem_resource.
>
> "Trying to free nonexistent resource <XXXXXXXXXXXXXXXX-YYYYYYYYYYYYYYYY>"
>
> release_mem_region() has been changed as called in each PAGES_PER_SECTION
> chunk since applying a patch(de7f0cba96786c). Because powerpc registers
> iomem_resource in each PAGES_PER_SECTION chunk. But when I hot add memory
> on x86 box, iomem_resource is register in each _CRS not PAGES_PER_SECTION
> chunk. So x86 box unregisters iomem_resource.
>
> The patch fixes the problem.
>
> CC: David Rientjes <rientjes@google.com>
> CC: Jiang Liu <liuj97@gmail.com>
> CC: Len Brown <len.brown@intel.com>
> CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> CC: Paul Mackerras <paulus@samba.org>
> CC: Christoph Lameter <cl@linux.com>
> Cc: Minchan Kim <minchan.kim@gmail.com>
> CC: Andrew Morton <akpm@linux-foundation.org>
> CC: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
> CC: Wen Congyang <wency@cn.fujitsu.com>
> Signed-off-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
> ---
>  arch/powerpc/platforms/pseries/hotplug-memory.c |   13 +++++++++----
>  mm/memory_hotplug.c                             |    4 ++--
>  2 files changed, 11 insertions(+), 6 deletions(-)
>
> Index: linux-3.6/arch/powerpc/platforms/pseries/hotplug-memory.c
> ===================================================================
> --- linux-3.6.orig/arch/powerpc/platforms/pseries/hotplug-memory.c      2012-10-04 14:22:59.833520792 +0900
> +++ linux-3.6/arch/powerpc/platforms/pseries/hotplug-memory.c   2012-10-04 14:23:05.150521411 +0900
> @@ -77,7 +77,8 @@ static int pseries_remove_memblock(unsig
>  {
>         unsigned long start, start_pfn;
>         struct zone *zone;
> -       int ret;
> +       int i, ret;
> +       int sections_to_remove;
>
>         start_pfn = base >> PAGE_SHIFT;
>
> @@ -97,9 +98,13 @@ static int pseries_remove_memblock(unsig
>          * to sysfs "state" file and we can't remove sysfs entries
>          * while writing to it. So we have to defer it to here.
>          */
> -       ret = __remove_pages(zone, start_pfn, memblock_size >> PAGE_SHIFT);
> -       if (ret)
> -               return ret;
> +       sections_to_remove = (memblock_size >> PAGE_SHIFT) / PAGES_PER_SECTION;
> +       for (i = 0; i < sections_to_remove; i++) {
> +               unsigned long pfn = start_pfn + i * PAGES_PER_SECTION;
> +               ret = __remove_pages(zone, start_pfn,  PAGES_PER_SECTION);
> +               if (ret)
> +                       return ret;
> +       }
>
>         /*
>          * Update memory regions for memory remove
> Index: linux-3.6/mm/memory_hotplug.c
> ===================================================================
> --- linux-3.6.orig/mm/memory_hotplug.c  2012-10-04 14:22:59.829520788 +0900
> +++ linux-3.6/mm/memory_hotplug.c       2012-10-04 14:23:25.860527278 +0900
> @@ -362,11 +362,11 @@ int __remove_pages(struct zone *zone, un
>         BUG_ON(phys_start_pfn & ~PAGE_SECTION_MASK);
>         BUG_ON(nr_pages % PAGES_PER_SECTION);
>
> +       release_mem_region(phys_start_pfn << PAGE_SHIFT, nr_pages * PAGE_SIZE);
> +
>         sections_to_remove = nr_pages / PAGES_PER_SECTION;
>         for (i = 0; i < sections_to_remove; i++) {
>                 unsigned long pfn = phys_start_pfn + i*PAGES_PER_SECTION;
> -               release_mem_region(pfn << PAGE_SHIFT,
> -                                  PAGES_PER_SECTION << PAGE_SHIFT);
>                 ret = __remove_section(zone, __pfn_to_section(pfn));
>                 if (ret)
>                         break;
>
> --
> To unsubscribe, send a message with 'unsubscribe linux-mm' in
> the body to majordomo@kvack.org.  For more info on Linux MM,
> see: http://www.linux-mm.org/ .
> Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply

* Re: [PATCHv2] PPC: Enable the Watchdog vector for 405
From: Jason Gunthorpe @ 2012-10-05 18:07 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
In-Reply-To: <1349348756.4260.15.camel@pasglop>

The watchdog and FIT code has been #if 0'd for ever, if the CPU takes
an exception to either of those vectors it will jump into the middle
of the PIT or Data TLB code and surely crash.

At least some (all?) 405 cores have both the WDT and FIT
vectors defined, so lets have proper entry points for them.

Tested that the WDT vector works on a 405F6 core.

Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
---
 arch/powerpc/kernel/head_40x.S |   47 ++++++++++++++++++++++++---------------
 arch/powerpc/kernel/traps.c    |    2 +-
 2 files changed, 30 insertions(+), 19 deletions(-)

Changes in v2:
 - Move all three exception vectors out of line with an explicit
   branch like exceptions-64.S (Benjamin)
 - Fix the #if .. | .. typo to be || (Josh)
 - Include the stub for FITException, and figured out what the very
   obsolete STDN_EXCEPTION might have done. (Benjamin)
 - I kept the WatchdogException trap unconditional, but this would be
   trivial to change, per Josh's comments

The disadvantage to moving the WDT out of line is that the
CRITICAL_EXCEPTION macro has to be expanded..

Thanks everyone

Action shot:

PowerPC Book-E Watchdog Exception
Oops: Watchdog Timeout
NIP: c0006b54 LR: c0006ad4 CTR: c003c800
REGS: c3ffbf50 TRAP: 1022   Not tainted  (3.6.0-00040-ga9db8b3)
MSR: 00029030 <EE,ME,IR,DR>  CR: 24002482  XER: 00000007
TASK = c03c32b0[0] 'swapper' THREAD: c03e0000
GPR00: 00000008 c03e1f90 c03c32b0 00000000 c1872f00 00000001 00000000 00000000 
GPR08: 01000000 c03e73c0 00000000 00000000 22000482 10152d00 7ffe7b60 7ffe7b70 
GPR16: 7ffe7be0 7ffe7d20 100f7560 7ffe7d9c 7ffe7db4 7ffe7d30 7ffe7dcc 7ffe7dd0 
GPR24: 00000000 00000000 00000000 c049e680 c03e0000 c03e003c 00000008 c03e0000 
NIP [c0006b54] cpu_idle+0xd0/0xe8
LR [c0006ad4] cpu_idle+0x50/0xe8
Call Trace:
[c03e1f90] [c0006ad4] cpu_idle+0x50/0xe8 (unreliable)
[c03e1fb0] [c0002990] rest_init+0x64/0x74
[c03e1fc0] [c0296774] start_kernel+0x2cc/0x2d4
[c03e1ff0] [c0002440] start_here+0x34/0x84
Instruction dump:
40820010 7c0000a6 60008000 7c000124 7c00e828 7c00f378 7c00e92d 40a2fff4 
4800000c 7c210b78 7ffffb78 801f003c <700b0004> 4182ff80 7c421378 48048585 
Kernel panic - not syncing: Watchdog Timeout
Call Trace:
Rebooting in 180 seconds..

diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S
index 4989661..8a9b6f5 100644
--- a/arch/powerpc/kernel/head_40x.S
+++ b/arch/powerpc/kernel/head_40x.S
@@ -430,30 +430,18 @@ label:
 	EXCEPTION(0x0F00, Trap_0F, unknown_exception, EXC_XFER_EE)
 
 /* 0x1000 - Programmable Interval Timer (PIT) Exception */
-	START_EXCEPTION(0x1000, Decrementer)
-	NORMAL_EXCEPTION_PROLOG
-	lis	r0,TSR_PIS@h
-	mtspr	SPRN_TSR,r0		/* Clear the PIT exception */
-	addi	r3,r1,STACK_FRAME_OVERHEAD
-	EXC_XFER_LITE(0x1000, timer_interrupt)
-
-#if 0
-/* NOTE:
- * FIT and WDT handlers are not implemented yet.
- */
+	. = 0x1000
+	b Decrementer
 
 /* 0x1010 - Fixed Interval Timer (FIT) Exception
 */
-	STND_EXCEPTION(0x1010,	FITException,		unknown_exception)
+	. = 0x1010
+	b FITException
 
 /* 0x1020 - Watchdog Timer (WDT) Exception
 */
-#ifdef CONFIG_BOOKE_WDT
-	CRITICAL_EXCEPTION(0x1020, WDTException, WatchdogException)
-#else
-	CRITICAL_EXCEPTION(0x1020, WDTException, unknown_exception)
-#endif
-#endif
+	. = 0x1020
+	b WDTException
 
 /* 0x1100 - Data TLB Miss Exception
  * As the name implies, translation is not in the MMU, so search the
@@ -738,6 +726,29 @@ label:
 		(MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \
 		NOCOPY, crit_transfer_to_handler, ret_from_crit_exc)
 
+	/* Programmable Interval Timer (PIT) Exception. (from 0x1000) */
+Decrementer:
+	NORMAL_EXCEPTION_PROLOG
+	lis	r0,TSR_PIS@h
+	mtspr	SPRN_TSR,r0		/* Clear the PIT exception */
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+	EXC_XFER_LITE(0x1000, timer_interrupt)
+
+	/* Fixed Interval Timer (FIT) Exception. (from 0x1010) */
+FITException:
+	NORMAL_EXCEPTION_PROLOG
+	addi	r3,r1,STACK_FRAME_OVERHEAD;
+	EXC_XFER_EE(0x1010, unknown_exception)
+
+	/* Watchdog Timer (WDT) Exception. (from 0x1020) */
+WDTException:
+	CRITICAL_EXCEPTION_PROLOG;
+	addi	r3,r1,STACK_FRAME_OVERHEAD;
+	EXC_XFER_TEMPLATE(WatchdogException, 0x1020+2,
+	                  (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)),
+			  NOCOPY, crit_transfer_to_handler,
+			  ret_from_crit_exc)
+
 /*
  * The other Data TLB exceptions bail out to this point
  * if they can't resolve the lightweight TLB fault.
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index ae0843f..eac1abf 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -1514,7 +1514,7 @@ void unrecoverable_exception(struct pt_regs *regs)
 	die("Unrecoverable exception", regs, SIGABRT);
 }
 
-#ifdef CONFIG_BOOKE_WDT
+#if defined(CONFIG_BOOKE_WDT) || defined(CONFIG_40x)
 /*
  * Default handler for a Watchdog exception,
  * spins until a reboot occurs
-- 
1.7.5.4

^ permalink raw reply related

* Re: [Cbe-oss-dev] [PATCH 4/5] Rename the drivers/of prom_* functions to of_*
From: Geoff Levand @ 2012-10-05 16:22 UTC (permalink / raw)
  To: Nathan Fontenot; +Cc: cbe-oss-dev, devicetree-discuss, linuxppc-dev, LKML
In-Reply-To: <506BA9E6.9050309@linux.vnet.ibm.com>

On Tue, 2012-10-02 at 21:58 -0500, Nathan Fontenot wrote:
> Rename the prom_*_property routines of the generic OF code to of_*_property.
> This brings them in line with the naming used by the rest of the OF code.
> 
> Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
> ---
>  arch/powerpc/platforms/ps3/os-area.c      |    6 +++---
>  10 files changed, 35 insertions(+), 37 deletions(-)

The ps3 part looks OK.  Please do build test with ps3_defconfig.

Acked-by: Geoff Levand <geoff@infradead.org>

^ permalink raw reply

* Re: PCI device not working
From: Kumar Gala @ 2012-10-05 12:47 UTC (permalink / raw)
  To: Davide Viti; +Cc: linuxppc-dev
In-Reply-To: <CAKpAL0mErR3vR4AdSAT_vJG_kM=GvHnZR+b3dtSCN0GMU56pAw@mail.gmail.com>


On Oct 5, 2012, at 3:54 AM, Davide Viti wrote:

> (just realized I did not send this to the mailing list: sorry for the =
noise)
>=20
> Hi Kumar,
>=20
> 2012/10/4 Kumar Gala <galak@kernel.crashing.org>:
>>=20
>> On Oct 4, 2012, at 7:24 AM, Davide Viti wrote:
>>=20
>>> Hi,
>>> it turns out that if define CONFIG_PCI_NOSCAN in u-boot (as per =
[1]), the
>>> device behind the second controller is detected by the  Linux =
kernel.
>>>=20
>>> Would
>>> you suggest any particular patch I should apply to fix this (I'm =
using kernel
>>> 2.6.34)
>>>=20
>>> thanx alot in advance
>>> Davide
>>>=20
>>> [1] http://permalink.gmane.org/gmane.linux.ports.ppc.embedded/20140
>>=20
>> My suggestion would be to try and dump all the controller registers =
between the case that works and doesn't and compare.  There's some minor =
setting difference that I'm guessing is causing issues.
>>=20
>> - k

When I said controller registers, I meant the FSL PCI controller and the =
CCSR registers not the PCI cfg register space

- k=

^ permalink raw reply

* Changing TASK_UNMAPPED_BASE to a low address
From: Thomas De Schampheleire @ 2012-10-05  9:47 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Ronny Meeus, patrickdepinguin+linuxppc

Hi,

The current virtual address space of a 32-bit userspace process looks
like this on powerpc:
# cat /proc/28922/maps
00100000-00102000 r-xp 00000000 00:00 0          [vdso]
0fe70000-0ffd8000 r-xp 00000000 00:01 754        /lib/libc-2.10.1.so
0ffd8000-0ffe8000 ---p 00168000 00:01 754        /lib/libc-2.10.1.so
0ffe8000-0ffea000 r--p 00168000 00:01 754        /lib/libc-2.10.1.so
0ffea000-0ffed000 rwxp 0016a000 00:01 754        /lib/libc-2.10.1.so
0ffed000-0fff0000 rwxp 00000000 00:00 0
10000000-10001000 r-xp 00000000 00:12 73         /tmp/memory_alloc
10010000-10011000 rwxp 00000000 00:12 73         /tmp/memory_alloc
10011000-47a32000 rwxp 00000000 00:00 0          [heap]
48000000-4801d000 r-xp 00000000 00:01 793        /lib/ld-2.10.1.so
4801d000-4801f000 rw-p 00000000 00:00 0
4801f000-48021000 rw-p 00000000 00:00 0
4802d000-4802e000 r--p 0001d000 00:01 793        /lib/ld-2.10.1.so
4802e000-4802f000 rwxp 0001e000 00:01 793        /lib/ld-2.10.1.so
4802f000-bf6ee000 rw-p 00000000 00:00 0
bfa18000-bfa39000 rw-p 00000000 00:00 0          [stack]

The process text and data area are at 0x10000000 (fixed), the
mmap_base is at 0x48000000 (TASK_UNMAPPED_BASE = 3/8*0xc0000000), and
shared libraries are put directly above 0x10000000.

When your application starts allocating memory, the first blocks are
taken starting from mmap_base (0x48000000) until you reached the stack
area (0xbfa18000 in this example). Then, a 'heap' region is created
after the process text/data area (0x10011000 in this example) and the
mmap_base (0x48000000). When this is also filled, any further
allocation fails.
However, between 0x0 and the first shared library, there is still
plenty of space. Without any shared library, there would be approx.
256 MB free. Even with a few shared libraries, this typically is >200
MB, at least in the type of applications I'm envisioning.

Because of the 3GB/1GB userspace/kernelspace virtual address split,
one expects an application to be able to allocate close to 3GB = 3072
MB. Due to the 256MB 'unused' area mentioned, you can only allocate
something like 2800 MB. If your application needs more than that, and
you're bound to 32-bit processors, this is a problem.

I've been looking at two ways to use the extra memory:
1. do an anonymous mmap with an address hint in that range, e.g. at
address 0x00110000. This does return memory, and if you know how much
is free there, you can take all of it.

2. change the TASK_UNMAPPED_BASE setting in the kernel
(arch/powerpc/include/asm/processor.h) to a low address, e.g. 0x40000.
The advantage of this is that applications need no change.

The second approach seems to work fine. The memory map changes to:

# cat /proc/6954/maps
00040000-0005d000 r-xp 00000000 00:01 787        /lib/ld-2.10.1.so
0005d000-0005f000 rw-p 00000000 00:00 0
0005f000-00061000 rw-p 00000000 00:00 0
0006d000-0006e000 r--p 0001d000 00:01 787        /lib/ld-2.10.1.so
0006e000-0006f000 rwxp 0001e000 00:01 787        /lib/ld-2.10.1.so
00100000-00102000 r-xp 00000000 00:00 0          [vdso]
00102000-0c904000 rw-p 00000000 00:00 0
0ca00000-0ca21000 rw-p 00000000 00:00 0
0ca21000-0cb00000 ---p 00000000 00:00 0
0fe70000-0ffd8000 r-xp 00000000 00:01 750        /lib/libc-2.10.1.so
0ffd8000-0ffe8000 ---p 00168000 00:01 750        /lib/libc-2.10.1.so
0ffe8000-0ffea000 r--p 00168000 00:01 750        /lib/libc-2.10.1.so
0ffea000-0ffed000 rwxp 0016a000 00:01 750        /lib/libc-2.10.1.so
0ffed000-0fff0000 rwxp 00000000 00:00 0
10000000-10001000 r-xp 00000000 00:12 119
/mnt/repo/tdescham/reborn/isam-linux-target-apps/memory_alloc
10010000-10011000 rwxp 00000000 00:12 119
/mnt/repo/tdescham/reborn/isam-linux-target-apps/memory_alloc
10011000-cb82f000 rw-p 00000000 00:00 0          [heap]
bffaf000-bffd0000 rw-p 00000000 00:00 0          [stack]


I have not seen anything 'weird' about this change.
I found the following thread that also discusses such a change:
https://lists.ozlabs.org/pipermail/linuxppc-dev/2004-February/016513.html
The thread talks about a few problems, but later concludes that these
have been fixed. Since the thread dates from 2004, I assume that
indeed this has been fixed.

Is there any reason why this change is not OK? I'm not necessarily
talking about mainlining the change. I first would like to know if it
is 'dangerous' or if there are other reasons not to do it.

This post is using linux-2.6.36.4 as base, but I looked at more recent
kernels and the settings seem the same.

Thanks,
Thomas

^ permalink raw reply

* Fwd: PCI device not working
From: Davide Viti @ 2012-10-05  8:54 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <CAKpAL0m3YnsbbGxL+ejfyE4zfGE5LD9Qxb7oobHVaAZGE1_Jnw@mail.gmail.com>

(just realized I did not send this to the mailing list: sorry for the noise)

Hi Kumar,

2012/10/4 Kumar Gala <galak@kernel.crashing.org>:
>
> On Oct 4, 2012, at 7:24 AM, Davide Viti wrote:
>
>> Hi,
>> it turns out that if define CONFIG_PCI_NOSCAN in u-boot (as per [1]), the
>> device behind the second controller is detected by the  Linux kernel.
>>
>> Would
>> you suggest any particular patch I should apply to fix this (I'm using kernel
>> 2.6.34)
>>
>> thanx alot in advance
>> Davide
>>
>> [1] http://permalink.gmane.org/gmane.linux.ports.ppc.embedded/20140
>
> My suggestion would be to try and dump all the controller registers between the case that works and doesn't and compare.  There's some minor setting difference that I'm guessing is causing issues.
>
> - k

Here's a diff for the configurations for the controller, obtained via

hexdump -C /sys/bus/pci/devices/0001\:02\:00.0/config

--- cfg0_2_NOK.txt      2012-10-05 09:37:44.854607000 +0200
+++ cfg0_2_OK.txt       2012-10-05 09:36:58.337399000 +0200

 00000400  00 00 00 00 16 00 00 00  e2 04 00 00 00 00 00 00  |................|
 00000410  04 00 00 00 01 00 00 00  00 00 00 00 40 40 00 00  |............@@..|
 00000420  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000430  00 00 00 00 00 00 00 00  21 81 9e 00 1a 90 01 00  |........!.......|
+00000430  00 00 00 00 00 00 00 00  21 81 9e 00 83 20 08 00  |........!.... ..|
 00000440  10 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000450  ce d7 14 00 20 1e fc 01  00 00 00 00 5c 0c 00 00  |.... .......\...|
 00000460  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000470  57 19 00 01 11 00 20 0b  00 00 00 00 01 00 00 00  |W..... .........|
 00000480  44 3d 00 00 00 00 00 00  f0 07 00 00 00 00 00 00  |D=..............|
 00000490  c0 07 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-000004a0  00 00 00 00 00 00 00 00  00 00 00 00 3c 01 00 00  |............<...|
+000004a0  00 00 00 00 00 00 00 00  00 00 00 00 7e 01 00 00  |............~...|
 000004b0  00 00 00 00 00 00 00 00  28 04 01 80 85 20 00 00  |........(.... ..|
 000004c0  ff 00 00 00 00 00 00 00  00 00 00 00 11 00 00 00  |................|
 000004d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 000004e0  00 00 00 00 01 01 00 00  01 01 00 00 00 00 00 00  |................|
-000004f0  0a 00 00 00 01 00 20 04  00 00 00 00 79 47 0e eb  |...... .....yG..|
+000004f0  4a 00 00 01 03 00 00 04  00 00 00 00 01 00 01 00  |J...............|
 00000500  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000510  00 00 00 00 00 00 00 00  21 01 00 00 00 00 00 00  |........!.......|
 00000520  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

Hope this mail client will not screw up the text...
Just in case,
I've pasted the entire register dumps to [1].

thank you so much for your time,
D.

[1] http://pastebin.com/zzAtzCeS

^ permalink raw reply

* [PATCH 10/10] memory-hotplug : remove sysfs file of node
From: Yasuaki Ishimatsu @ 2012-10-05  2:38 UTC (permalink / raw)
  To: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
	linux-sh, linux-ia64, cmetcalf, sparclinux
  Cc: len.brown, wency, Yasuaki Ishimatsu, minchan.kim, kosaki.motohiro,
	rientjes, cl, akpm, liuj97
In-Reply-To: <506E43E0.70507@jp.fujitsu.com>

From: Wen Congyang <wency@cn.fujitsu.com>

This patch introduces a new function try_offline_node() to
remove sysfs file of node when all memory sections of this
node are removed. If some memory sections of this node are
not removed, this function does nothing.

CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <liuj97@gmail.com>
CC: Len Brown <len.brown@intel.com>
CC: Christoph Lameter <cl@linux.com>
Cc: Minchan Kim <minchan.kim@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
CC: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 mm/memory_hotplug.c |   54 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)

Index: linux-3.6/mm/memory_hotplug.c
===================================================================
--- linux-3.6.orig/mm/memory_hotplug.c	2012-10-04 18:30:31.767709165 +0900
+++ linux-3.6/mm/memory_hotplug.c	2012-10-04 18:32:46.907842637 +0900
@@ -29,6 +29,7 @@
 #include <linux/suspend.h>
 #include <linux/mm_inline.h>
 #include <linux/firmware-map.h>
+#include <linux/stop_machine.h>
 
 #include <asm/tlbflush.h>
 
@@ -1276,6 +1277,57 @@ int offline_memory(u64 start, u64 size)
 	return 0;
 }
 
+static int check_cpu_on_node(void *data)
+{
+	struct pglist_data *pgdat = data;
+	int cpu;
+
+	for_each_online_cpu(cpu) {
+		if (cpu_to_node(cpu) == pgdat->node_id)
+			/*
+			 * the cpu on this node is onlined, and we can't
+			 * offline this node.
+			 */
+			return -EBUSY;
+	}
+
+	return 0;
+}
+
+/* offline the node if all memory sections of this node are removed */
+static void try_offline_node(int nid)
+{
+	unsigned long start_pfn = NODE_DATA(nid)->node_start_pfn;
+	unsigned long end_pfn = start_pfn + NODE_DATA(nid)->node_spanned_pages;
+	unsigned long pfn;
+
+	for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
+		unsigned long section_nr = pfn_to_section_nr(pfn);
+
+		if (!present_section_nr(section_nr))
+			continue;
+
+		if (pfn_to_nid(pfn) != nid)
+			continue;
+
+		/*
+		 * some memory sections of this node are not removed, and we
+		 * can't offline node now.
+		 */
+		return;
+	}
+
+	if (stop_machine(check_cpu_on_node, NODE_DATA(nid), NULL))
+		return;
+
+	/*
+	 * all memory sections of this node are removed, we can offline this
+	 * node now.
+	 */
+	node_set_offline(nid);
+	unregister_one_node(nid);
+}
+
 int __ref remove_memory(int nid, u64 start, u64 size)
 {
 	int ret = 0;
@@ -1296,6 +1348,8 @@ int __ref remove_memory(int nid, u64 sta
 	firmware_map_remove(start, start + size, "System RAM");
 
 	arch_remove_memory(start, size);
+
+	try_offline_node(nid);
 out:
 	unlock_memory_hotplug();
 	return ret;

^ permalink raw reply

* [PATCH 9/10] memory-hotplug : memory_hotplug: clear zone when removing the memory
From: Yasuaki Ishimatsu @ 2012-10-05  2:37 UTC (permalink / raw)
  To: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
	linux-sh, linux-ia64, cmetcalf, sparclinux
  Cc: len.brown, wency, Yasuaki Ishimatsu, minchan.kim, kosaki.motohiro,
	rientjes, cl, akpm, liuj97
In-Reply-To: <506E43E0.70507@jp.fujitsu.com>

When a memory is added, we update zone's and pgdat's start_pfn and
spanned_pages in the function __add_zone(). So we should revert them
when the memory is removed.

The patch adds a new function __remove_zone() to do this.

CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <liuj97@gmail.com>
CC: Len Brown <len.brown@intel.com>
CC: Christoph Lameter <cl@linux.com>
Cc: Minchan Kim <minchan.kim@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 mm/memory_hotplug.c |  207 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 207 insertions(+)

Index: linux-3.6/mm/memory_hotplug.c
===================================================================
--- linux-3.6.orig/mm/memory_hotplug.c	2012-10-04 18:30:21.182698427 +0900
+++ linux-3.6/mm/memory_hotplug.c	2012-10-04 18:30:31.767709165 +0900
@@ -312,10 +312,213 @@ static int __meminit __add_section(int n
 	return register_new_memory(nid, __pfn_to_section(phys_start_pfn));
 }
 
+/* find the smallest valid pfn in the range [start_pfn, end_pfn) */
+static int find_smallest_section_pfn(int nid, struct zone *zone,
+				     unsigned long start_pfn,
+				     unsigned long end_pfn)
+{
+	struct mem_section *ms;
+
+	for (; start_pfn < end_pfn; start_pfn += PAGES_PER_SECTION) {
+		ms = __pfn_to_section(start_pfn);
+
+		if (unlikely(!valid_section(ms)))
+			continue;
+
+		if (unlikely(pfn_to_nid(start_pfn)) != nid)
+			continue;
+
+		if (zone && zone != page_zone(pfn_to_page(start_pfn)))
+			continue;
+
+		return start_pfn;
+	}
+
+	return 0;
+}
+
+/* find the biggest valid pfn in the range [start_pfn, end_pfn). */
+static int find_biggest_section_pfn(int nid, struct zone *zone,
+				    unsigned long start_pfn,
+				    unsigned long end_pfn)
+{
+	struct mem_section *ms;
+	unsigned long pfn;
+
+	/* pfn is the end pfn of a memory section. */
+	pfn = end_pfn - 1;
+	for (; pfn >= start_pfn; pfn -= PAGES_PER_SECTION) {
+		ms = __pfn_to_section(pfn);
+
+		if (unlikely(!valid_section(ms)))
+			continue;
+
+		if (unlikely(pfn_to_nid(pfn)) != nid)
+			continue;
+
+		if (zone && zone != page_zone(pfn_to_page(pfn)))
+			continue;
+
+		return pfn;
+	}
+
+	return 0;
+}
+
+static void shrink_zone_span(struct zone *zone, unsigned long start_pfn,
+			     unsigned long end_pfn)
+{
+	unsigned long zone_start_pfn =  zone->zone_start_pfn;
+	unsigned long zone_end_pfn = zone->zone_start_pfn + zone->spanned_pages;
+	unsigned long pfn;
+	struct mem_section *ms;
+	int nid = zone_to_nid(zone);
+
+	zone_span_writelock(zone);
+	if (zone_start_pfn == start_pfn) {
+		/*
+		 * If the section is smallest section in the zone, it need
+		 * shrink zone->zone_start_pfn and zone->zone_spanned_pages.
+		 * In this case, we find second smallest valid mem_section
+		 * for shrinking zone.
+		 */
+		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;
+		}
+	} else if (zone_end_pfn == end_pfn) {
+		/*
+		 * If the section is biggest section in the zone, it need
+		 * shrink zone->spanned_pages.
+		 * In this case, we find second biggest valid mem_section for
+		 * shrinking zone.
+		 */
+		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(!valid_section(ms)))
+			continue;
+
+		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;
+	}
+
+	/* The zone has no valid section */
+	zone->zone_start_pfn = 0;
+	zone->spanned_pages = 0;
+	zone_span_writeunlock(zone);
+}
+
+static void shrink_pgdat_span(struct pglist_data *pgdat,
+			      unsigned long start_pfn, unsigned long end_pfn)
+{
+	unsigned long pgdat_start_pfn =  pgdat->node_start_pfn;
+	unsigned long pgdat_end_pfn =
+		pgdat->node_start_pfn + pgdat->node_spanned_pages;
+	unsigned long pfn;
+	struct mem_section *ms;
+	int nid = pgdat->node_id;
+
+	if (pgdat_start_pfn == start_pfn) {
+		/*
+		 * If the section is smallest section in the pgdat, it need
+		 * shrink pgdat->node_start_pfn and pgdat->node_spanned_pages.
+		 * In this case, we find second smallest valid mem_section
+		 * for shrinking zone.
+		 */
+		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;
+		}
+	} else if (pgdat_end_pfn == end_pfn) {
+		/*
+		 * If the section is biggest section in the pgdat, it need
+		 * shrink pgdat->node_spanned_pages.
+		 * In this case, we find second biggest valid mem_section for
+		 * shrinking zone.
+		 */
+		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(!valid_section(ms)))
+			continue;
+
+		if (pfn_to_nid(pfn) != nid)
+			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 */
+		return;
+	}
+
+	/* The pgdat has no valid section */
+	pgdat->node_start_pfn = 0;
+	pgdat->node_spanned_pages = 0;
+}
+
+static void __remove_zone(struct zone *zone, unsigned long start_pfn)
+{
+	struct pglist_data *pgdat = zone->zone_pgdat;
+	int nr_pages = PAGES_PER_SECTION;
+	int zone_type;
+	unsigned long flags;
+
+	zone_type = zone - pgdat->node_zones;
+
+	pgdat_resize_lock(zone->zone_pgdat, &flags);
+	shrink_zone_span(zone, start_pfn, start_pfn + nr_pages);
+	shrink_pgdat_span(pgdat, start_pfn, start_pfn + nr_pages);
+	pgdat_resize_unlock(zone->zone_pgdat, &flags);
+}
+
 static int __remove_section(struct zone *zone, struct mem_section *ms)
 {
 	unsigned long flags;
 	struct pglist_data *pgdat = zone->zone_pgdat;
+	unsigned long start_pfn;
+	int scn_nr;
 	int ret = -EINVAL;
 
 	if (!valid_section(ms))
@@ -325,6 +528,10 @@ static int __remove_section(struct zone 
 	if (ret)
 		return ret;
 
+	scn_nr = __section_nr(ms);
+	start_pfn = section_nr_to_pfn(scn_nr);
+	__remove_zone(zone, start_pfn);
+
 	pgdat_resize_lock(pgdat, &flags);
 	sparse_remove_one_section(zone, ms);
 	pgdat_resize_unlock(pgdat, &flags);

^ permalink raw reply

* [PATCH 8/10] memory-hotplug : remove page table of x86_64 architecture
From: Yasuaki Ishimatsu @ 2012-10-05  2:36 UTC (permalink / raw)
  To: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
	linux-sh, linux-ia64, cmetcalf, sparclinux
  Cc: len.brown, wency, Yasuaki Ishimatsu, minchan.kim, kosaki.motohiro,
	rientjes, cl, akpm, liuj97
In-Reply-To: <506E43E0.70507@jp.fujitsu.com>

From: Wen Congyang <wency@cn.fujitsu.com>

For hot removing memory, we sholud remove page table about the memory.
So the patch searches a page table about the removed memory, and clear
page table.

CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <liuj97@gmail.com>
CC: Len Brown <len.brown@intel.com>
CC: Christoph Lameter <cl@linux.com>
Cc: Minchan Kim <minchan.kim@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
CC: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 arch/x86/include/asm/pgtable_types.h |    1 
 arch/x86/mm/init_64.c                |  147 +++++++++++++++++++++++++++++++++++
 arch/x86/mm/pageattr.c               |   47 +++++------
 3 files changed, 173 insertions(+), 22 deletions(-)

Index: linux-3.6/arch/x86/mm/init_64.c
===================================================================
--- linux-3.6.orig/arch/x86/mm/init_64.c	2012-10-04 18:30:21.171698416 +0900
+++ linux-3.6/arch/x86/mm/init_64.c	2012-10-04 18:30:27.317704652 +0900
@@ -675,6 +675,151 @@ int arch_add_memory(int nid, u64 start, 
 }
 EXPORT_SYMBOL_GPL(arch_add_memory);
 
+static void __meminit
+phys_pte_remove(pte_t *pte_page, unsigned long addr, unsigned long end)
+{
+	unsigned pages = 0;
+	int i = pte_index(addr);
+
+	pte_t *pte = pte_page + pte_index(addr);
+
+	for (; i < PTRS_PER_PTE; i++, addr += PAGE_SIZE, pte++) {
+
+		if (addr >= end)
+			break;
+
+		if (!pte_present(*pte))
+			continue;
+
+		pages++;
+		set_pte(pte, __pte(0));
+	}
+
+	update_page_count(PG_LEVEL_4K, -pages);
+}
+
+static void __meminit
+phys_pmd_remove(pmd_t *pmd_page, unsigned long addr, unsigned long end)
+{
+	unsigned long pages = 0, next;
+	int i = pmd_index(addr);
+
+	for (; i < PTRS_PER_PMD; i++, addr = next) {
+		unsigned long pte_phys;
+		pmd_t *pmd = pmd_page + pmd_index(addr);
+		pte_t *pte;
+
+		if (addr >= end)
+			break;
+
+		next = (addr & PMD_MASK) + PMD_SIZE;
+
+		if (!pmd_present(*pmd))
+			continue;
+
+		if (pmd_large(*pmd)) {
+			if ((addr & ~PMD_MASK) == 0 && next <= end) {
+				set_pmd(pmd, __pmd(0));
+				pages++;
+				continue;
+			}
+
+			/*
+			 * We use 2M page, but we need to remove part of them,
+			 * so split 2M page to 4K page.
+			 */
+			pte = alloc_low_page(&pte_phys);
+			__split_large_page((pte_t *)pmd, addr, pte);
+
+			spin_lock(&init_mm.page_table_lock);
+			pmd_populate_kernel(&init_mm, pmd, __va(pte_phys));
+			spin_unlock(&init_mm.page_table_lock);
+		}
+
+		spin_lock(&init_mm.page_table_lock);
+		pte = map_low_page((pte_t *)pmd_page_vaddr(*pmd));
+		phys_pte_remove(pte, addr, end);
+		unmap_low_page(pte);
+		spin_unlock(&init_mm.page_table_lock);
+	}
+	update_page_count(PG_LEVEL_2M, -pages);
+}
+
+static void __meminit
+phys_pud_remove(pud_t *pud_page, unsigned long addr, unsigned long end)
+{
+	unsigned long pages = 0, next;
+	int i = pud_index(addr);
+
+	for (; i < PTRS_PER_PUD; i++, addr = next) {
+		unsigned long pmd_phys;
+		pud_t *pud = pud_page + pud_index(addr);
+		pmd_t *pmd;
+
+		if (addr >= end)
+			break;
+
+		next = (addr & PUD_MASK) + PUD_SIZE;
+
+		if (!pud_present(*pud))
+			continue;
+
+		if (pud_large(*pud)) {
+			if ((addr & ~PUD_MASK) == 0 && next <= end) {
+				set_pud(pud, __pud(0));
+				pages++;
+				continue;
+			}
+
+			/*
+			 * We use 1G page, but we need to remove part of them,
+			 * so split 1G page to 2M page.
+			 */
+			pmd = alloc_low_page(&pmd_phys);
+			__split_large_page((pte_t *)pud, addr, (pte_t *)pmd);
+
+			spin_lock(&init_mm.page_table_lock);
+			pud_populate(&init_mm, pud, __va(pmd_phys));
+			spin_unlock(&init_mm.page_table_lock);
+		}
+
+		pmd = map_low_page(pmd_offset(pud, 0));
+		phys_pmd_remove(pmd, addr, end);
+		unmap_low_page(pmd);
+		__flush_tlb_all();
+	}
+	__flush_tlb_all();
+
+	update_page_count(PG_LEVEL_1G, -pages);
+}
+
+void __meminit
+kernel_physical_mapping_remove(unsigned long start, unsigned long end)
+{
+	unsigned long next;
+
+	start = (unsigned long)__va(start);
+	end = (unsigned long)__va(end);
+
+	for (; start < end; start = next) {
+		pgd_t *pgd = pgd_offset_k(start);
+		pud_t *pud;
+
+		next = (start + PGDIR_SIZE) & PGDIR_MASK;
+		if (next > end)
+			next = end;
+
+		if (!pgd_present(*pgd))
+			continue;
+
+		pud = map_low_page((pud_t *)pgd_page_vaddr(*pgd));
+		phys_pud_remove(pud, __pa(start), __pa(end));
+		unmap_low_page(pud);
+	}
+
+	__flush_tlb_all();
+}
+
 #ifdef CONFIG_MEMORY_HOTREMOVE
 int __ref arch_remove_memory(u64 start, u64 size)
 {
@@ -687,6 +832,8 @@ int __ref arch_remove_memory(u64 start, 
 	ret = __remove_pages(zone, start_pfn, nr_pages);
 	WARN_ON_ONCE(ret);
 
+	kernel_physical_mapping_remove(start, start + size);
+
 	return ret;
 }
 #endif
Index: linux-3.6/arch/x86/include/asm/pgtable_types.h
===================================================================
--- linux-3.6.orig/arch/x86/include/asm/pgtable_types.h	2012-10-04 18:26:51.925486954 +0900
+++ linux-3.6/arch/x86/include/asm/pgtable_types.h	2012-10-04 18:30:27.322704656 +0900
@@ -334,6 +334,7 @@ static inline void update_page_count(int
  * as a pte too.
  */
 extern pte_t *lookup_address(unsigned long address, unsigned int *level);
+extern int __split_large_page(pte_t *kpte, unsigned long address, pte_t *pbase);
 
 #endif	/* !__ASSEMBLY__ */
 
Index: linux-3.6/arch/x86/mm/pageattr.c
===================================================================
--- linux-3.6.orig/arch/x86/mm/pageattr.c	2012-10-04 18:26:51.923486952 +0900
+++ linux-3.6/arch/x86/mm/pageattr.c	2012-10-04 18:30:27.328704662 +0900
@@ -501,21 +501,13 @@ out_unlock:
 	return do_split;
 }
 
-static int split_large_page(pte_t *kpte, unsigned long address)
+int __split_large_page(pte_t *kpte, unsigned long address, pte_t *pbase)
 {
 	unsigned long pfn, pfninc = 1;
 	unsigned int i, level;
-	pte_t *pbase, *tmp;
+	pte_t *tmp;
 	pgprot_t ref_prot;
-	struct page *base;
-
-	if (!debug_pagealloc)
-		spin_unlock(&cpa_lock);
-	base = alloc_pages(GFP_KERNEL | __GFP_NOTRACK, 0);
-	if (!debug_pagealloc)
-		spin_lock(&cpa_lock);
-	if (!base)
-		return -ENOMEM;
+	struct page *base = virt_to_page(pbase);
 
 	spin_lock(&pgd_lock);
 	/*
@@ -523,10 +515,11 @@ static int split_large_page(pte_t *kpte,
 	 * up for us already:
 	 */
 	tmp = lookup_address(address, &level);
-	if (tmp != kpte)
-		goto out_unlock;
+	if (tmp != kpte) {
+		spin_unlock(&pgd_lock);
+		return 1;
+	}
 
-	pbase = (pte_t *)page_address(base);
 	paravirt_alloc_pte(&init_mm, page_to_pfn(base));
 	ref_prot = pte_pgprot(pte_clrhuge(*kpte));
 	/*
@@ -579,17 +572,27 @@ static int split_large_page(pte_t *kpte,
 	 * going on.
 	 */
 	__flush_tlb_all();
+	spin_unlock(&pgd_lock);
 
-	base = NULL;
+	return 0;
+}
 
-out_unlock:
-	/*
-	 * If we dropped out via the lookup_address check under
-	 * pgd_lock then stick the page back into the pool:
-	 */
-	if (base)
+static int split_large_page(pte_t *kpte, unsigned long address)
+{
+	pte_t *pbase;
+	struct page *base;
+
+	if (!debug_pagealloc)
+		spin_unlock(&cpa_lock);
+	base = alloc_pages(GFP_KERNEL | __GFP_NOTRACK, 0);
+	if (!debug_pagealloc)
+		spin_lock(&cpa_lock);
+	if (!base)
+		return -ENOMEM;
+
+	pbase = (pte_t *)page_address(base);
+	if (__split_large_page(kpte, address, pbase))
 		__free_page(base);
-	spin_unlock(&pgd_lock);
 
 	return 0;
 }

^ permalink raw reply

* [PATCH 7/10] memory-hotplug : remove memmap of sparse-vmemmap
From: Yasuaki Ishimatsu @ 2012-10-05  2:34 UTC (permalink / raw)
  To: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
	linux-sh, linux-ia64, cmetcalf, sparclinux
  Cc: len.brown, wency, Yasuaki Ishimatsu, minchan.kim, kosaki.motohiro,
	rientjes, cl, akpm, liuj97
In-Reply-To: <506E43E0.70507@jp.fujitsu.com>

All pages of virtual mapping in removed memory cannot be freed, since some pages
used as PGD/PUD includes not only removed memory but also other memory. So the
patch checks whether page can be freed or not.

How to check whether page can be freed or not?
 1. When removing memory, the page structs of the revmoved memory are filled
    with 0FD.
 2. All page structs are filled with 0xFD on PT/PMD, PT/PMD can be cleared.
    In this case, the page used as PT/PMD can be freed.

Applying patch, __remove_section() of CONFIG_SPARSEMEM_VMEMMAP is integrated
into one. So __remove_section() of CONFIG_SPARSEMEM_VMEMMAP is deleted.

Note:  vmemmap_kfree() and vmemmap_free_bootmem() are not implemented for ia64,
ppc, s390, and sparc.

CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <liuj97@gmail.com>
CC: Len Brown <len.brown@intel.com>
CC: Christoph Lameter <cl@linux.com>
Cc: Minchan Kim <minchan.kim@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
CC: Wen Congyang <wency@cn.fujitsu.com>
Signed-off-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
---
 arch/ia64/mm/discontig.c  |    8 +++
 arch/powerpc/mm/init_64.c |    8 +++
 arch/s390/mm/vmem.c       |    8 +++
 arch/sparc/mm/init_64.c   |    8 +++
 arch/x86/mm/init_64.c     |  119 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/mm.h        |    2 
 mm/memory_hotplug.c       |   17 ------
 mm/sparse.c               |    5 +
 8 files changed, 158 insertions(+), 17 deletions(-)

Index: linux-3.6/arch/ia64/mm/discontig.c
===================================================================
--- linux-3.6.orig/arch/ia64/mm/discontig.c	2012-10-04 18:30:15.475692638 +0900
+++ linux-3.6/arch/ia64/mm/discontig.c	2012-10-04 18:30:21.145698389 +0900
@@ -823,6 +823,14 @@ int __meminit vmemmap_populate(struct pa
 	return vmemmap_populate_basepages(start_page, size, node);
 }
 
+void vmemmap_kfree(struct page *memmap, unsigned long nr_pages)
+{
+}
+
+void vmemmap_free_bootmem(struct page *memmap, unsigned long nr_pages)
+{
+}
+
 void register_page_bootmem_memmap(unsigned long section_nr,
 				  struct page *start_page, unsigned long size)
 {
Index: linux-3.6/arch/powerpc/mm/init_64.c
===================================================================
--- linux-3.6.orig/arch/powerpc/mm/init_64.c	2012-10-04 18:30:15.494692657 +0900
+++ linux-3.6/arch/powerpc/mm/init_64.c	2012-10-04 18:30:21.150698394 +0900
@@ -299,6 +299,14 @@ int __meminit vmemmap_populate(struct pa
 	return 0;
 }
 
+void vmemmap_kfree(struct page *memmap, unsigned long nr_pages)
+{
+}
+
+void vmemmap_free_bootmem(struct page *memmap, unsigned long nr_pages)
+{
+}
+
 void register_page_bootmem_memmap(unsigned long section_nr,
 				  struct page *start_page, unsigned long size)
 {
Index: linux-3.6/arch/s390/mm/vmem.c
===================================================================
--- linux-3.6.orig/arch/s390/mm/vmem.c	2012-10-04 18:30:15.506692670 +0900
+++ linux-3.6/arch/s390/mm/vmem.c	2012-10-04 18:30:21.157698401 +0900
@@ -227,6 +227,14 @@ out:
 	return ret;
 }
 
+void vmemmap_kfree(struct page *memmap, unsigned long nr_pages)
+{
+}
+
+void vmemmap_free_bootmem(struct page *memmap, unsigned long nr_pages)
+{
+}
+
 void register_page_bootmem_memmap(unsigned long section_nr,
 				  struct page *start_page, unsigned long size)
 {
Index: linux-3.6/arch/sparc/mm/init_64.c
===================================================================
--- linux-3.6.orig/arch/sparc/mm/init_64.c	2012-10-04 18:30:15.512692676 +0900
+++ linux-3.6/arch/sparc/mm/init_64.c	2012-10-04 18:30:21.163698408 +0900
@@ -2078,6 +2078,14 @@ void __meminit vmemmap_populate_print_la
 	}
 }
 
+void vmemmap_kfree(struct page *memmap, unsigned long nr_pages)
+{
+}
+
+void vmemmap_free_bootmem(struct page *memmap, unsigned long nr_pages)
+{
+}
+
 void register_page_bootmem_memmap(unsigned long section_nr,
 				  struct page *start_page, unsigned long size)
 {
Index: linux-3.6/arch/x86/mm/init_64.c
===================================================================
--- linux-3.6.orig/arch/x86/mm/init_64.c	2012-10-04 18:30:15.517692681 +0900
+++ linux-3.6/arch/x86/mm/init_64.c	2012-10-04 18:30:21.171698416 +0900
@@ -993,6 +993,125 @@ vmemmap_populate(struct page *start_page
 	return 0;
 }
 
+#define PAGE_INUSE 0xFD
+
+unsigned long find_and_clear_pte_page(unsigned long addr, unsigned long end,
+			    struct page **pp, int *page_size)
+{
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+	pte_t *pte;
+	void *page_addr;
+	unsigned long next;
+
+	*pp = NULL;
+
+	pgd = pgd_offset_k(addr);
+	if (pgd_none(*pgd))
+		return pgd_addr_end(addr, end);
+
+	pud = pud_offset(pgd, addr);
+	if (pud_none(*pud))
+		return pud_addr_end(addr, end);
+
+	if (!cpu_has_pse) {
+		next = (addr + PAGE_SIZE) & PAGE_MASK;
+		pmd = pmd_offset(pud, addr);
+		if (pmd_none(*pmd))
+			return next;
+
+		pte = pte_offset_kernel(pmd, addr);
+		if (pte_none(*pte))
+			return next;
+
+		*page_size = PAGE_SIZE;
+		*pp = pte_page(*pte);
+	} else {
+		next = pmd_addr_end(addr, end);
+
+		pmd = pmd_offset(pud, addr);
+		if (pmd_none(*pmd))
+			return next;
+
+		*page_size = PMD_SIZE;
+		*pp = pmd_page(*pmd);
+	}
+
+	/*
+	 * Removed page structs are filled with 0xFD.
+	 */
+	memset((void *)addr, PAGE_INUSE, next - addr);
+
+	page_addr = page_address(*pp);
+
+	/*
+	 * Check the page is filled with 0xFD or not.
+	 * memchr_inv() returns the address. In this case, we cannot
+	 * clear PTE/PUD entry, since the page is used by other.
+	 * So we cannot also free the page.
+	 *
+	 * memchr_inv() returns NULL. In this case, we can clear
+	 * PTE/PUD entry, since the page is not used by other.
+	 * So we can also free the page.
+	 */
+	if (memchr_inv(page_addr, PAGE_INUSE, *page_size)) {
+		*pp = NULL;
+		return next;
+	}
+
+	if (!cpu_has_pse)
+		pte_clear(&init_mm, addr, pte);
+	else
+		pmd_clear(pmd);
+
+	return next;
+}
+
+void vmemmap_kfree(struct page *memmap, unsigned long nr_pages)
+{
+	unsigned long addr = (unsigned long)memmap;
+	unsigned long end = (unsigned long)(memmap + nr_pages);
+	unsigned long next;
+	struct page *page;
+	int page_size;
+
+	for (; addr < end; addr = next) {
+		page = NULL;
+		page_size = 0;
+		next = find_and_clear_pte_page(addr, end, &page, &page_size);
+		if (!page)
+			continue;
+
+		free_pages((unsigned long)page_address(page),
+			    get_order(page_size));
+		__flush_tlb_one(addr);
+	}
+}
+
+void vmemmap_free_bootmem(struct page *memmap, unsigned long nr_pages)
+{
+	unsigned long addr = (unsigned long)memmap;
+	unsigned long end = (unsigned long)(memmap + nr_pages);
+	unsigned long next;
+	struct page *page;
+	int page_size;
+	unsigned long magic;
+
+	for (; addr < end; addr = next) {
+		page = NULL;
+		page_size = 0;
+		next = find_and_clear_pte_page(addr, end, &page, &page_size);
+		if (!page)
+			continue;
+
+		magic = (unsigned long) page->lru.next;
+		if (magic == SECTION_INFO)
+			put_page_bootmem(page);
+		flush_tlb_kernel_range(addr, end);
+	}
+}
+
 void register_page_bootmem_memmap(unsigned long section_nr,
 				  struct page *start_page, unsigned long size)
 {
Index: linux-3.6/include/linux/mm.h
===================================================================
--- linux-3.6.orig/include/linux/mm.h	2012-10-04 18:30:15.524692688 +0900
+++ linux-3.6/include/linux/mm.h	2012-10-04 18:30:21.177698422 +0900
@@ -1620,6 +1620,8 @@ int vmemmap_populate(struct page *start_
 void vmemmap_populate_print_last(void);
 void register_page_bootmem_memmap(unsigned long section_nr, struct page *map,
 				  unsigned long size);
+void vmemmap_kfree(struct page *memmpa, unsigned long nr_pages);
+void vmemmap_free_bootmem(struct page *memmpa, unsigned long nr_pages);
 
 enum mf_flags {
 	MF_COUNT_INCREASED = 1 << 0,
Index: linux-3.6/mm/memory_hotplug.c
===================================================================
--- linux-3.6.orig/mm/memory_hotplug.c	2012-10-04 18:30:15.464692627 +0900
+++ linux-3.6/mm/memory_hotplug.c	2012-10-04 18:30:21.182698427 +0900
@@ -312,19 +312,6 @@ static int __meminit __add_section(int n
 	return register_new_memory(nid, __pfn_to_section(phys_start_pfn));
 }
 
-#ifdef CONFIG_SPARSEMEM_VMEMMAP
-static int __remove_section(struct zone *zone, struct mem_section *ms)
-{
-	int ret = -EINVAL;
-
-	if (!valid_section(ms))
-		return ret;
-
-	ret = unregister_memory_section(ms);
-
-	return ret;
-}
-#else
 static int __remove_section(struct zone *zone, struct mem_section *ms)
 {
 	unsigned long flags;
@@ -341,9 +328,9 @@ static int __remove_section(struct zone 
 	pgdat_resize_lock(pgdat, &flags);
 	sparse_remove_one_section(zone, ms);
 	pgdat_resize_unlock(pgdat, &flags);
-	return 0;
+
+	return ret;
 }
-#endif
 
 /*
  * Reasonably generic function for adding memory.  It is
Index: linux-3.6/mm/sparse.c
===================================================================
--- linux-3.6.orig/mm/sparse.c	2012-10-04 18:26:53.908488966 +0900
+++ linux-3.6/mm/sparse.c	2012-10-04 18:30:21.185698430 +0900
@@ -613,12 +613,13 @@ static inline struct page *kmalloc_secti
 	/* This will make the necessary allocations eventually. */
 	return sparse_mem_map_populate(pnum, nid);
 }
-static void __kfree_section_memmap(struct page *memmap, unsigned long nr_pages)
+static void __kfree_section_memmap(struct page *page, unsigned long nr_pages)
 {
-	return; /* XXX: Not implemented yet */
+	vmemmap_kfree(page, nr_pages);
 }
 static void free_map_bootmem(struct page *page, unsigned long nr_pages)
 {
+	vmemmap_free_bootmem(page, nr_pages);
 }
 #else
 static struct page *__kmalloc_section_memmap(unsigned long nr_pages)

^ permalink raw reply

* [PATCH 6/10] memory-hotplug : implement register_page_bootmem_info_section of sparse-vmemmap
From: Yasuaki Ishimatsu @ 2012-10-05  2:33 UTC (permalink / raw)
  To: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
	linux-sh, linux-ia64, cmetcalf, sparclinux
  Cc: len.brown, wency, Yasuaki Ishimatsu, minchan.kim, kosaki.motohiro,
	rientjes, cl, akpm, liuj97
In-Reply-To: <506E43E0.70507@jp.fujitsu.com>

For removing memmap region of sparse-vmemmap which is allocated bootmem,
memmap region of sparse-vmemmap needs to be registered by get_page_bootmem().
So the patch searches pages of virtual mapping and registers the pages by
get_page_bootmem().

Note: register_page_bootmem_memmap() is not implemented for ia64, ppc, s390,
and sparc.

CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <liuj97@gmail.com>
CC: Len Brown <len.brown@intel.com>
CC: Christoph Lameter <cl@linux.com>
Cc: Minchan Kim <minchan.kim@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
Signed-off-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
---
 arch/ia64/mm/discontig.c       |    6 ++++
 arch/powerpc/mm/init_64.c      |    6 ++++
 arch/s390/mm/vmem.c            |    6 ++++
 arch/sparc/mm/init_64.c        |    6 ++++
 arch/x86/mm/init_64.c          |   52 +++++++++++++++++++++++++++++++++++++++++
 include/linux/memory_hotplug.h |   11 +-------
 include/linux/mm.h             |    3 +-
 mm/memory_hotplug.c            |   37 ++++++++++++++++++++++++++---
 8 files changed, 113 insertions(+), 14 deletions(-)

Index: linux-3.6/include/linux/memory_hotplug.h
===================================================================
--- linux-3.6.orig/include/linux/memory_hotplug.h	2012-10-04 17:15:03.029828127 +0900
+++ linux-3.6/include/linux/memory_hotplug.h	2012-10-04 17:15:59.010833688 +0900
@@ -163,17 +163,10 @@ static inline void arch_refresh_nodedata
 #endif /* CONFIG_NUMA */
 #endif /* CONFIG_HAVE_ARCH_NODEDATA_EXTENSION */
 
-#ifdef CONFIG_SPARSEMEM_VMEMMAP
-static inline void register_page_bootmem_info_node(struct pglist_data *pgdat)
-{
-}
-static inline void put_page_bootmem(struct page *page)
-{
-}
-#else
 extern void register_page_bootmem_info_node(struct pglist_data *pgdat);
 extern void put_page_bootmem(struct page *page);
-#endif
+extern void get_page_bootmem(unsigned long ingo, struct page *page,
+			     unsigned long type);
 
 /*
  * Lock for memory hotplug guarantees 1) all callbacks for memory hotplug
Index: linux-3.6/mm/memory_hotplug.c
===================================================================
--- linux-3.6.orig/mm/memory_hotplug.c	2012-10-04 17:15:27.213831361 +0900
+++ linux-3.6/mm/memory_hotplug.c	2012-10-04 17:37:00.176401540 +0900
@@ -91,9 +91,8 @@ static void release_memory_resource(stru
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
-#ifndef CONFIG_SPARSEMEM_VMEMMAP
-static void get_page_bootmem(unsigned long info,  struct page *page,
-			     unsigned long type)
+void get_page_bootmem(unsigned long info,  struct page *page,
+		      unsigned long type)
 {
 	unsigned long page_type;
 
@@ -127,6 +126,7 @@ void __ref put_page_bootmem(struct page 
 
 }
 
+#ifndef CONFIG_SPARSEMEM_VMEMMAP
 static void register_page_bootmem_info_section(unsigned long start_pfn)
 {
 	unsigned long *usemap, mapsize, section_nr, i;
@@ -160,6 +160,36 @@ static void register_page_bootmem_info_s
 		get_page_bootmem(section_nr, page, MIX_SECTION_INFO);
 
 }
+#else
+static void register_page_bootmem_info_section(unsigned long start_pfn)
+{
+	unsigned long *usemap, mapsize, section_nr, i;
+	struct mem_section *ms;
+	struct page *page, *memmap;
+
+	if (!pfn_valid(start_pfn))
+		return;
+
+	section_nr = pfn_to_section_nr(start_pfn);
+	ms = __nr_to_section(section_nr);
+
+	memmap = sparse_decode_mem_map(ms->section_mem_map, section_nr);
+
+	page = virt_to_page(memmap);
+	mapsize = sizeof(struct page) * PAGES_PER_SECTION;
+	mapsize = PAGE_ALIGN(mapsize) >> PAGE_SHIFT;
+
+	register_page_bootmem_memmap(section_nr, memmap, PAGES_PER_SECTION);
+
+	usemap = __nr_to_section(section_nr)->pageblock_flags;
+	page = virt_to_page(usemap);
+
+	mapsize = PAGE_ALIGN(usemap_size()) >> PAGE_SHIFT;
+
+	for (i = 0; i < mapsize; i++, page++)
+		get_page_bootmem(section_nr, page, MIX_SECTION_INFO);
+}
+#endif
 
 void register_page_bootmem_info_node(struct pglist_data *pgdat)
 {
@@ -202,7 +232,6 @@ void register_page_bootmem_info_node(str
 			register_page_bootmem_info_section(pfn);
 	}
 }
-#endif /* !CONFIG_SPARSEMEM_VMEMMAP */
 
 static void grow_zone_span(struct zone *zone, unsigned long start_pfn,
 			   unsigned long end_pfn)
Index: linux-3.6/arch/ia64/mm/discontig.c
===================================================================
--- linux-3.6.orig/arch/ia64/mm/discontig.c	2012-10-01 08:47:46.000000000 +0900
+++ linux-3.6/arch/ia64/mm/discontig.c	2012-10-04 17:15:59.209833459 +0900
@@ -822,4 +822,10 @@ int __meminit vmemmap_populate(struct pa
 {
 	return vmemmap_populate_basepages(start_page, size, node);
 }
+
+void register_page_bootmem_memmap(unsigned long section_nr,
+				  struct page *start_page, unsigned long size)
+{
+	/* TODO */
+}
 #endif
Index: linux-3.6/arch/powerpc/mm/init_64.c
===================================================================
--- linux-3.6.orig/arch/powerpc/mm/init_64.c	2012-10-01 08:47:46.000000000 +0900
+++ linux-3.6/arch/powerpc/mm/init_64.c	2012-10-04 17:15:59.217833663 +0900
@@ -298,5 +298,11 @@ int __meminit vmemmap_populate(struct pa
 
 	return 0;
 }
+
+void register_page_bootmem_memmap(unsigned long section_nr,
+				  struct page *start_page, unsigned long size)
+{
+	/* TODO */
+}
 #endif /* CONFIG_SPARSEMEM_VMEMMAP */
 
Index: linux-3.6/arch/s390/mm/vmem.c
===================================================================
--- linux-3.6.orig/arch/s390/mm/vmem.c	2012-10-01 08:47:46.000000000 +0900
+++ linux-3.6/arch/s390/mm/vmem.c	2012-10-04 17:15:59.227833764 +0900
@@ -227,6 +227,12 @@ out:
 	return ret;
 }
 
+void register_page_bootmem_memmap(unsigned long section_nr,
+				  struct page *start_page, unsigned long size)
+{
+	/* TODO */
+}
+
 /*
  * Add memory segment to the segment list if it doesn't overlap with
  * an already present segment.
Index: linux-3.6/arch/sparc/mm/init_64.c
===================================================================
--- linux-3.6.orig/arch/sparc/mm/init_64.c	2012-10-01 08:47:46.000000000 +0900
+++ linux-3.6/arch/sparc/mm/init_64.c	2012-10-04 17:15:59.232833747 +0900
@@ -2077,6 +2077,12 @@ void __meminit vmemmap_populate_print_la
 		node_start = 0;
 	}
 }
+
+void register_page_bootmem_memmap(unsigned long section_nr,
+				  struct page *start_page, unsigned long size)
+{
+	/* TODO */
+}
 #endif /* CONFIG_SPARSEMEM_VMEMMAP */
 
 static void prot_init_common(unsigned long page_none,
Index: linux-3.6/arch/x86/mm/init_64.c
===================================================================
--- linux-3.6.orig/arch/x86/mm/init_64.c	2012-10-04 17:15:03.021828121 +0900
+++ linux-3.6/arch/x86/mm/init_64.c	2012-10-04 17:15:59.240833769 +0900
@@ -993,6 +993,58 @@ vmemmap_populate(struct page *start_page
 	return 0;
 }
 
+void register_page_bootmem_memmap(unsigned long section_nr,
+				  struct page *start_page, unsigned long size)
+{
+	unsigned long addr = (unsigned long)start_page;
+	unsigned long end = (unsigned long)(start_page + size);
+	unsigned long next;
+	pgd_t *pgd;
+	pud_t *pud;
+	pmd_t *pmd;
+
+	for (; addr < end; addr = next) {
+		pte_t *pte = NULL;
+
+		pgd = pgd_offset_k(addr);
+		if (pgd_none(*pgd)) {
+			next = (addr + PAGE_SIZE) & PAGE_MASK;
+			continue;
+		}
+		get_page_bootmem(section_nr, pgd_page(*pgd), MIX_SECTION_INFO);
+
+		pud = pud_offset(pgd, addr);
+		if (pud_none(*pud)) {
+			next = (addr + PAGE_SIZE) & PAGE_MASK;
+			continue;
+		}
+		get_page_bootmem(section_nr, pud_page(*pud), MIX_SECTION_INFO);
+
+		if (!cpu_has_pse) {
+			next = (addr + PAGE_SIZE) & PAGE_MASK;
+			pmd = pmd_offset(pud, addr);
+			if (pmd_none(*pmd))
+				continue;
+			get_page_bootmem(section_nr, pmd_page(*pmd),
+					 MIX_SECTION_INFO);
+
+			pte = pte_offset_kernel(pmd, addr);
+			if (pte_none(*pte))
+				continue;
+			get_page_bootmem(section_nr, pte_page(*pte),
+					 SECTION_INFO);
+		} else {
+			next = pmd_addr_end(addr, end);
+
+			pmd = pmd_offset(pud, addr);
+			if (pmd_none(*pmd))
+				continue;
+			get_page_bootmem(section_nr, pmd_page(*pmd),
+					 SECTION_INFO);
+		}
+	}
+}
+
 void __meminit vmemmap_populate_print_last(void)
 {
 	if (p_start) {
Index: linux-3.6/include/linux/mm.h
===================================================================
--- linux-3.6.orig/include/linux/mm.h	2012-10-01 08:47:46.000000000 +0900
+++ linux-3.6/include/linux/mm.h	2012-10-04 17:15:59.246833767 +0900
@@ -1618,7 +1618,8 @@ int vmemmap_populate_basepages(struct pa
 						unsigned long pages, int node);
 int vmemmap_populate(struct page *start_page, unsigned long pages, int node);
 void vmemmap_populate_print_last(void);
-
+void register_page_bootmem_memmap(unsigned long section_nr, struct page *map,
+				  unsigned long size);
 
 enum mf_flags {
 	MF_COUNT_INCREASED = 1 << 0,

^ permalink raw reply

* [PATCH 5/10] memory-hotplug : memory-hotplug: check page type in get_page_bootmem
From: Yasuaki Ishimatsu @ 2012-10-05  2:32 UTC (permalink / raw)
  To: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
	linux-sh, linux-ia64, cmetcalf, sparclinux
  Cc: len.brown, wency, Yasuaki Ishimatsu, minchan.kim, kosaki.motohiro,
	rientjes, cl, akpm, liuj97
In-Reply-To: <506E43E0.70507@jp.fujitsu.com>

The function get_page_bootmem() may be called more than one time to the same
page. There is no need to set page's type, private if the function is not
the first time called to the page.

Note: the patch is just optimization and does not fix any problem.

CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <liuj97@gmail.com>
CC: Len Brown <len.brown@intel.com>
CC: Christoph Lameter <cl@linux.com>
Cc: Minchan Kim <minchan.kim@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
CC: Wen Congyang <wency@cn.fujitsu.com>
Signed-off-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
---
 mm/memory_hotplug.c |   15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

Index: linux-3.6/mm/memory_hotplug.c
===================================================================
--- linux-3.6.orig/mm/memory_hotplug.c	2012-10-04 18:29:58.284676075 +0900
+++ linux-3.6/mm/memory_hotplug.c	2012-10-04 18:30:03.454680542 +0900
@@ -95,10 +95,17 @@ static void release_memory_resource(stru
 static void get_page_bootmem(unsigned long info,  struct page *page,
 			     unsigned long type)
 {
-	page->lru.next = (struct list_head *) type;
-	SetPagePrivate(page);
-	set_page_private(page, info);
-	atomic_inc(&page->_count);
+	unsigned long page_type;
+
+	page_type = (unsigned long)page->lru.next;
+	if (page_type < MEMORY_HOTPLUG_MIN_BOOTMEM_TYPE ||
+	    page_type > MEMORY_HOTPLUG_MAX_BOOTMEM_TYPE){
+		page->lru.next = (struct list_head *)type;
+		SetPagePrivate(page);
+		set_page_private(page, info);
+		atomic_inc(&page->_count);
+	} else
+		atomic_inc(&page->_count);
 }
 
 /* reference to __meminit __free_pages_bootmem is valid

^ permalink raw reply

* [PATCH 4/10] memory-hotplug : unregister memory section on SPARSEMEM_VMEMMAP
From: Yasuaki Ishimatsu @ 2012-10-05  2:31 UTC (permalink / raw)
  To: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
	linux-sh, linux-ia64, cmetcalf, sparclinux
  Cc: len.brown, wency, Yasuaki Ishimatsu, minchan.kim, kosaki.motohiro,
	rientjes, cl, akpm, liuj97
In-Reply-To: <506E43E0.70507@jp.fujitsu.com>

Currently __remove_section for SPARSEMEM_VMEMMAP does nothing. But even if
we use SPARSEMEM_VMEMMAP, we can unregister the memory_section.

So the patch add unregister_memory_section() into __remove_section().

CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <liuj97@gmail.com>
CC: Len Brown <len.brown@intel.com>
CC: Christoph Lameter <cl@linux.com>
Cc: Minchan Kim <minchan.kim@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> 
CC: Wen Congyang <wency@cn.fujitsu.com>
Signed-off-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
---
 mm/memory_hotplug.c |   13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

Index: linux-3.6/mm/memory_hotplug.c
===================================================================
--- linux-3.6.orig/mm/memory_hotplug.c	2012-10-04 18:29:50.577668254 +0900
+++ linux-3.6/mm/memory_hotplug.c	2012-10-04 18:29:58.284676075 +0900
@@ -279,11 +279,14 @@ static int __meminit __add_section(int n
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
 static int __remove_section(struct zone *zone, struct mem_section *ms)
 {
-	/*
-	 * XXX: Freeing memmap with vmemmap is not implement yet.
-	 *      This should be removed later.
-	 */
-	return -EBUSY;
+	int ret = -EINVAL;
+
+	if (!valid_section(ms))
+		return ret;
+
+	ret = unregister_memory_section(ms);
+
+	return ret;
 }
 #else
 static int __remove_section(struct zone *zone, struct mem_section *ms)

^ permalink raw reply

* [PATCH 3/10] memory-hotplug : introduce new function arch_remove_memory() for removing page table depends on architecture
From: Yasuaki Ishimatsu @ 2012-10-05  2:29 UTC (permalink / raw)
  To: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
	linux-sh, linux-ia64, cmetcalf, sparclinux
  Cc: len.brown, wency, Yasuaki Ishimatsu, minchan.kim, kosaki.motohiro,
	rientjes, cl, akpm, liuj97
In-Reply-To: <506E43E0.70507@jp.fujitsu.com>

From: Wen Congyang <wency@cn.fujitsu.com>

For removing memory, we need to remove page table. But it depends
on architecture. So the patch introduce arch_remove_memory() for
removing page table. Now it only calls __remove_pages().

Note: __remove_pages() for some archtecuture is not implemented
      (I don't know how to implement it for s390).

CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <liuj97@gmail.com>
CC: Len Brown <len.brown@intel.com>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <paulus@samba.org>
CC: Christoph Lameter <cl@linux.com>
Cc: Minchan Kim <minchan.kim@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
CC: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
---
 arch/ia64/mm/init.c            |   18 ++++++++++++++++++
 arch/powerpc/mm/mem.c          |   12 ++++++++++++
 arch/s390/mm/init.c            |   12 ++++++++++++
 arch/sh/mm/init.c              |   17 +++++++++++++++++
 arch/tile/mm/init.c            |    8 ++++++++
 arch/x86/mm/init_32.c          |   12 ++++++++++++
 arch/x86/mm/init_64.c          |   15 +++++++++++++++
 include/linux/memory_hotplug.h |    1 +
 mm/memory_hotplug.c            |    1 +
 9 files changed, 96 insertions(+)

Index: linux-3.6/arch/ia64/mm/init.c
===================================================================
--- linux-3.6.orig/arch/ia64/mm/init.c	2012-10-04 18:27:03.082498276 +0900
+++ linux-3.6/arch/ia64/mm/init.c	2012-10-04 18:28:50.087606867 +0900
@@ -688,6 +688,24 @@ int arch_add_memory(int nid, u64 start, 
 
 	return ret;
 }
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+int arch_remove_memory(u64 start, u64 size)
+{
+	unsigned long start_pfn = start >> PAGE_SHIFT;
+	unsigned long nr_pages = size >> PAGE_SHIFT;
+	struct zone *zone;
+	int ret;
+
+	zone = page_zone(pfn_to_page(start_pfn));
+	ret = __remove_pages(zone, start_pfn, nr_pages);
+	if (ret)
+		pr_warn("%s: Problem encountered in __remove_pages() as"
+			" ret=%d\n", __func__,  ret);
+
+	return ret;
+}
+#endif
 #endif
 
 /*
Index: linux-3.6/arch/powerpc/mm/mem.c
===================================================================
--- linux-3.6.orig/arch/powerpc/mm/mem.c	2012-10-04 18:27:03.084498278 +0900
+++ linux-3.6/arch/powerpc/mm/mem.c	2012-10-04 18:28:50.094606874 +0900
@@ -133,6 +133,18 @@ int arch_add_memory(int nid, u64 start, 
 
 	return __add_pages(nid, zone, start_pfn, nr_pages);
 }
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+int arch_remove_memory(u64 start, u64 size)
+{
+	unsigned long start_pfn = start >> PAGE_SHIFT;
+	unsigned long nr_pages = size >> PAGE_SHIFT;
+	struct zone *zone;
+
+	zone = page_zone(pfn_to_page(start_pfn));
+	return __remove_pages(zone, start_pfn, nr_pages);
+}
+#endif
 #endif /* CONFIG_MEMORY_HOTPLUG */
 
 /*
Index: linux-3.6/arch/s390/mm/init.c
===================================================================
--- linux-3.6.orig/arch/s390/mm/init.c	2012-10-04 18:27:03.080498274 +0900
+++ linux-3.6/arch/s390/mm/init.c	2012-10-04 18:28:50.104606884 +0900
@@ -257,4 +257,16 @@ int arch_add_memory(int nid, u64 start, 
 		vmem_remove_mapping(start, size);
 	return rc;
 }
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+int arch_remove_memory(u64 start, u64 size)
+{
+	/*
+	 * There is no hardware or firmware interface which could trigger a
+	 * hot memory remove on s390. So there is nothing that needs to be
+	 * implemented.
+	 */
+	return -EBUSY;
+}
+#endif
 #endif /* CONFIG_MEMORY_HOTPLUG */
Index: linux-3.6/arch/sh/mm/init.c
===================================================================
--- linux-3.6.orig/arch/sh/mm/init.c	2012-10-04 18:27:03.091498285 +0900
+++ linux-3.6/arch/sh/mm/init.c	2012-10-04 18:28:50.116606897 +0900
@@ -558,4 +558,21 @@ int memory_add_physaddr_to_nid(u64 addr)
 EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
 #endif
 
+#ifdef CONFIG_MEMORY_HOTREMOVE
+int arch_remove_memory(u64 start, u64 size)
+{
+	unsigned long start_pfn = start >> PAGE_SHIFT;
+	unsigned long nr_pages = size >> PAGE_SHIFT;
+	struct zone *zone;
+	int ret;
+
+	zone = page_zone(pfn_to_page(start_pfn));
+	ret = __remove_pages(zone, start_pfn, nr_pages);
+	if (unlikely(ret))
+		pr_warn("%s: Failed, __remove_pages() == %d\n", __func__,
+			ret);
+
+	return ret;
+}
+#endif
 #endif /* CONFIG_MEMORY_HOTPLUG */
Index: linux-3.6/arch/tile/mm/init.c
===================================================================
--- linux-3.6.orig/arch/tile/mm/init.c	2012-10-04 18:27:03.078498272 +0900
+++ linux-3.6/arch/tile/mm/init.c	2012-10-04 18:28:50.122606903 +0900
@@ -935,6 +935,14 @@ int remove_memory(u64 start, u64 size)
 {
 	return -EINVAL;
 }
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+int arch_remove_memory(u64 start, u64 size)
+{
+	/* TODO */
+	return -EBUSY;
+}
+#endif
 #endif
 
 struct kmem_cache *pgd_cache;
Index: linux-3.6/arch/x86/mm/init_32.c
===================================================================
--- linux-3.6.orig/arch/x86/mm/init_32.c	2012-10-04 18:27:03.089498283 +0900
+++ linux-3.6/arch/x86/mm/init_32.c	2012-10-04 18:28:50.128606909 +0900
@@ -842,6 +842,18 @@ int arch_add_memory(int nid, u64 start, 
 
 	return __add_pages(nid, zone, start_pfn, nr_pages);
 }
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+int arch_remove_memory(u64 start, u64 size)
+{
+	unsigned long start_pfn = start >> PAGE_SHIFT;
+	unsigned long nr_pages = size >> PAGE_SHIFT;
+	struct zone *zone;
+
+	zone = page_zone(pfn_to_page(start_pfn));
+	return __remove_pages(zone, start_pfn, nr_pages);
+}
+#endif
 #endif
 
 /*
Index: linux-3.6/arch/x86/mm/init_64.c
===================================================================
--- linux-3.6.orig/arch/x86/mm/init_64.c	2012-10-04 18:27:03.086498280 +0900
+++ linux-3.6/arch/x86/mm/init_64.c	2012-10-04 18:28:50.132606913 +0900
@@ -675,6 +675,21 @@ int arch_add_memory(int nid, u64 start, 
 }
 EXPORT_SYMBOL_GPL(arch_add_memory);
 
+#ifdef CONFIG_MEMORY_HOTREMOVE
+int __ref arch_remove_memory(u64 start, u64 size)
+{
+	unsigned long start_pfn = start >> PAGE_SHIFT;
+	unsigned long nr_pages = size >> PAGE_SHIFT;
+	struct zone *zone;
+	int ret;
+
+	zone = page_zone(pfn_to_page(start_pfn));
+	ret = __remove_pages(zone, start_pfn, nr_pages);
+	WARN_ON_ONCE(ret);
+
+	return ret;
+}
+#endif
 #endif /* CONFIG_MEMORY_HOTPLUG */
 
 static struct kcore_list kcore_vsyscall;
Index: linux-3.6/include/linux/memory_hotplug.h
===================================================================
--- linux-3.6.orig/include/linux/memory_hotplug.h	2012-10-04 18:27:03.094498288 +0900
+++ linux-3.6/include/linux/memory_hotplug.h	2012-10-04 18:28:50.137606918 +0900
@@ -85,6 +85,7 @@ extern void __online_page_free(struct pa
 
 #ifdef CONFIG_MEMORY_HOTREMOVE
 extern bool is_pageblock_removable_nolock(struct page *page);
+extern int arch_remove_memory(u64 start, u64 size);
 #endif /* CONFIG_MEMORY_HOTREMOVE */
 
 /* reasonably generic interface to expand the physical pages in a zone  */
Index: linux-3.6/mm/memory_hotplug.c
===================================================================
--- linux-3.6.orig/mm/memory_hotplug.c	2012-10-04 18:28:42.851599524 +0900
+++ linux-3.6/mm/memory_hotplug.c	2012-10-04 18:29:50.577668254 +0900
@@ -1062,6 +1062,7 @@ int __ref remove_memory(int nid, u64 sta
 	/* remove memmap entry */
 	firmware_map_remove(start, start + size, "System RAM");
 
+	arch_remove_memory(start, size);
 out:
 	unlock_memory_hotplug();
 	return ret;

^ permalink raw reply

* [PATCH 2/10] memory-hotplug : remove /sys/firmware/memmap/X sysfs
From: Yasuaki Ishimatsu @ 2012-10-05  2:26 UTC (permalink / raw)
  To: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
	linux-sh, linux-ia64, cmetcalf, sparclinux
  Cc: len.brown, wency, Yasuaki Ishimatsu, minchan.kim, kosaki.motohiro,
	rientjes, cl, akpm, liuj97
In-Reply-To: <506E43E0.70507@jp.fujitsu.com>

When (hot)adding memory into system, /sys/firmware/memmap/X/{end, start, type}
sysfs files are created. But there is no code to remove these files. The patch
implements the function to remove them.

Note : The code does not free firmware_map_entry since there is no way to free
       memory which is allocated by bootmem.

CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <liuj97@gmail.com>
CC: Len Brown <len.brown@intel.com>
CC: Christoph Lameter <cl@linux.com>
Cc: Minchan Kim <minchan.kim@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> 
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
Signed-off-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>

---
 drivers/firmware/memmap.c    |   98 ++++++++++++++++++++++++++++++++++++++++++-
 include/linux/firmware-map.h |    6 ++
 mm/memory_hotplug.c          |    7 ++-
 3 files changed, 108 insertions(+), 3 deletions(-)

Index: linux-3.6/drivers/firmware/memmap.c
===================================================================
--- linux-3.6.orig/drivers/firmware/memmap.c	2012-10-04 18:27:05.195500420 +0900
+++ linux-3.6/drivers/firmware/memmap.c	2012-10-04 18:27:18.901514330 +0900
@@ -21,6 +21,7 @@
 #include <linux/types.h>
 #include <linux/bootmem.h>
 #include <linux/slab.h>
+#include <linux/mm.h>
 
 /*
  * Data types ------------------------------------------------------------------
@@ -41,6 +42,7 @@ struct firmware_map_entry {
 	const char		*type;	/* type of the memory range */
 	struct list_head	list;	/* entry for the linked list */
 	struct kobject		kobj;   /* kobject for each entry */
+	unsigned int		bootmem:1; /* allocated from bootmem */
 };
 
 /*
@@ -79,7 +81,26 @@ static const struct sysfs_ops memmap_att
 	.show = memmap_attr_show,
 };
 
+
+static inline struct firmware_map_entry *
+to_memmap_entry(struct kobject *kobj)
+{
+	return container_of(kobj, struct firmware_map_entry, kobj);
+}
+
+static void release_firmware_map_entry(struct kobject *kobj)
+{
+	struct firmware_map_entry *entry = to_memmap_entry(kobj);
+
+	if (entry->bootmem)
+		/* There is no way to free memory allocated from bootmem */
+		return;
+
+	kfree(entry);
+}
+
 static struct kobj_type memmap_ktype = {
+	.release	= release_firmware_map_entry,
 	.sysfs_ops	= &memmap_attr_ops,
 	.default_attrs	= def_attrs,
 };
@@ -94,6 +115,7 @@ static struct kobj_type memmap_ktype = {
  * in firmware initialisation code in one single thread of execution.
  */
 static LIST_HEAD(map_entries);
+static DEFINE_SPINLOCK(map_entries_lock);
 
 /**
  * firmware_map_add_entry() - Does the real work to add a firmware memmap entry.
@@ -118,11 +140,25 @@ static int firmware_map_add_entry(u64 st
 	INIT_LIST_HEAD(&entry->list);
 	kobject_init(&entry->kobj, &memmap_ktype);
 
+	spin_lock(&map_entries_lock);
 	list_add_tail(&entry->list, &map_entries);
+	spin_unlock(&map_entries_lock);
 
 	return 0;
 }
 
+/**
+ * firmware_map_remove_entry() - Does the real work to remove a firmware
+ * memmap entry.
+ * @entry: removed entry.
+ **/
+static inline void firmware_map_remove_entry(struct firmware_map_entry *entry)
+{
+	spin_lock(&map_entries_lock);
+	list_del(&entry->list);
+	spin_unlock(&map_entries_lock);
+}
+
 /*
  * Add memmap entry on sysfs
  */
@@ -144,6 +180,35 @@ static int add_sysfs_fw_map_entry(struct
 	return 0;
 }
 
+/*
+ * Remove memmap entry on sysfs
+ */
+static inline void remove_sysfs_fw_map_entry(struct firmware_map_entry *entry)
+{
+	kobject_put(&entry->kobj);
+}
+
+/*
+ * Search memmap entry
+ */
+
+static struct firmware_map_entry * __meminit
+firmware_map_find_entry(u64 start, u64 end, const char *type)
+{
+	struct firmware_map_entry *entry;
+
+	spin_lock(&map_entries_lock);
+	list_for_each_entry(entry, &map_entries, list)
+		if ((entry->start == start) && (entry->end == end) &&
+		    (!strcmp(entry->type, type))) {
+			spin_unlock(&map_entries_lock);
+			return entry;
+		}
+
+	spin_unlock(&map_entries_lock);
+	return NULL;
+}
+
 /**
  * firmware_map_add_hotplug() - Adds a firmware mapping entry when we do
  * memory hotplug.
@@ -193,9 +258,36 @@ int __init firmware_map_add_early(u64 st
 	if (WARN_ON(!entry))
 		return -ENOMEM;
 
+	entry->bootmem = 1;
 	return firmware_map_add_entry(start, end, type, entry);
 }
 
+/**
+ * firmware_map_remove() - remove a firmware mapping entry
+ * @start: Start of the memory range.
+ * @end:   End of the memory range.
+ * @type:  Type of the memory range.
+ *
+ * removes a firmware mapping entry.
+ *
+ * Returns 0 on success, or -EINVAL if no entry.
+ **/
+int __meminit firmware_map_remove(u64 start, u64 end, const char *type)
+{
+	struct firmware_map_entry *entry;
+
+	entry = firmware_map_find_entry(start, end - 1, type);
+	if (!entry)
+		return -EINVAL;
+
+	firmware_map_remove_entry(entry);
+
+	/* remove the memmap entry */
+	remove_sysfs_fw_map_entry(entry);
+
+	return 0;
+}
+
 /*
  * Sysfs functions -------------------------------------------------------------
  */
@@ -217,8 +309,10 @@ static ssize_t type_show(struct firmware
 	return snprintf(buf, PAGE_SIZE, "%s\n", entry->type);
 }
 
-#define to_memmap_attr(_attr) container_of(_attr, struct memmap_attribute, attr)
-#define to_memmap_entry(obj) container_of(obj, struct firmware_map_entry, kobj)
+static inline struct memmap_attribute *to_memmap_attr(struct attribute *attr)
+{
+	return container_of(attr, struct memmap_attribute, attr);
+}
 
 static ssize_t memmap_attr_show(struct kobject *kobj,
 				struct attribute *attr, char *buf)
Index: linux-3.6/include/linux/firmware-map.h
===================================================================
--- linux-3.6.orig/include/linux/firmware-map.h	2012-10-04 18:27:05.197500422 +0900
+++ linux-3.6/include/linux/firmware-map.h	2012-10-04 18:27:18.904514333 +0900
@@ -25,6 +25,7 @@
 
 int firmware_map_add_early(u64 start, u64 end, const char *type);
 int firmware_map_add_hotplug(u64 start, u64 end, const char *type);
+int firmware_map_remove(u64 start, u64 end, const char *type);
 
 #else /* CONFIG_FIRMWARE_MEMMAP */
 
@@ -38,6 +39,11 @@ static inline int firmware_map_add_hotpl
 	return 0;
 }
 
+static inline int firmware_map_remove(u64 start, u64 end, const char *type)
+{
+	return 0;
+}
+
 #endif /* CONFIG_FIRMWARE_MEMMAP */
 
 #endif /* _LINUX_FIRMWARE_MAP_H */
Index: linux-3.6/mm/memory_hotplug.c
===================================================================
--- linux-3.6.orig/mm/memory_hotplug.c	2012-10-04 18:27:03.000000000 +0900
+++ linux-3.6/mm/memory_hotplug.c	2012-10-04 18:28:42.851599524 +0900
@@ -1043,7 +1043,7 @@ int offline_memory(u64 start, u64 size)
 	return 0;
 }
 
-int remove_memory(int nid, u64 start, u64 size)
+int __ref remove_memory(int nid, u64 start, u64 size)
 {
 	int ret = 0;
 	lock_memory_hotplug();
@@ -1056,8 +1056,13 @@ int remove_memory(int nid, u64 start, u6
 			"because the memmory range is online\n",
 			start, start + size);
 		ret = -EAGAIN;
+		goto out;
 	}
 
+	/* remove memmap entry */
+	firmware_map_remove(start, start + size, "System RAM");
+
+out:
 	unlock_memory_hotplug();
 	return ret;
 }

^ permalink raw reply

* [PATCH 1/10] memory-hotplug : check whether memory is offline or not when removing memory
From: Yasuaki Ishimatsu @ 2012-10-05  2:25 UTC (permalink / raw)
  To: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
	linux-sh, linux-ia64, cmetcalf, sparclinux
  Cc: len.brown, wency, Yasuaki Ishimatsu, minchan.kim, kosaki.motohiro,
	rientjes, cl, akpm, liuj97
In-Reply-To: <506E43E0.70507@jp.fujitsu.com>

When calling remove_memory(), the memory should be offline. If the function
is used to online memory, kernel panic may occur.

So the patch checks whether memory is offline or not.

CC: David Rientjes <rientjes@google.com>
CC: Jiang Liu <liuj97@gmail.com>
CC: Len Brown <len.brown@intel.com>
CC: Christoph Lameter <cl@linux.com>
Cc: Minchan Kim <minchan.kim@gmail.com>
CC: Andrew Morton <akpm@linux-foundation.org>
CC: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> 
Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
Signed-off-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>

---
 drivers/base/memory.c  |   39 +++++++++++++++++++++++++++++++++++++++
 include/linux/memory.h |    5 +++++
 mm/memory_hotplug.c    |   17 +++++++++++++++--
 3 files changed, 59 insertions(+), 2 deletions(-)

Index: linux-3.6/drivers/base/memory.c
===================================================================
--- linux-3.6.orig/drivers/base/memory.c	2012-10-04 14:22:57.000000000 +0900
+++ linux-3.6/drivers/base/memory.c	2012-10-04 14:45:46.653585860 +0900
@@ -70,6 +70,45 @@ void unregister_memory_isolate_notifier(
 }
 EXPORT_SYMBOL(unregister_memory_isolate_notifier);
 
+bool is_memblk_offline(unsigned long start, unsigned long size)
+{
+	struct memory_block *mem = NULL;
+	struct mem_section *section;
+	unsigned long start_pfn, end_pfn;
+	unsigned long pfn, section_nr;
+
+	start_pfn = PFN_DOWN(start);
+	end_pfn = PFN_UP(start + size);
+
+	for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
+		section_nr = pfn_to_section_nr(pfn);
+		if (!present_section_nr(section_nr))
+			continue;
+
+		section = __nr_to_section(section_nr);
+		/* same memblock? */
+		if (mem)
+			if ((section_nr >= mem->start_section_nr) &&
+			    (section_nr <= mem->end_section_nr))
+				continue;
+
+		mem = find_memory_block_hinted(section, mem);
+		if (!mem)
+			continue;
+		if (mem->state == MEM_OFFLINE)
+			continue;
+
+		kobject_put(&mem->dev.kobj);
+		return false;
+	}
+
+	if (mem)
+		kobject_put(&mem->dev.kobj);
+
+	return true;
+}
+EXPORT_SYMBOL(is_memblk_offline);
+
 /*
  * register_memory - Setup a sysfs device for a memory block
  */
Index: linux-3.6/include/linux/memory.h
===================================================================
--- linux-3.6.orig/include/linux/memory.h	2012-10-02 18:00:22.000000000 +0900
+++ linux-3.6/include/linux/memory.h	2012-10-04 14:44:40.902581028 +0900
@@ -106,6 +106,10 @@ static inline int memory_isolate_notify(
 {
 	return 0;
 }
+static inline bool is_memblk_offline(unsigned long start, unsigned long size)
+{
+	return false;
+}
 #else
 extern int register_memory_notifier(struct notifier_block *nb);
 extern void unregister_memory_notifier(struct notifier_block *nb);
@@ -120,6 +124,7 @@ extern int memory_isolate_notify(unsigne
 extern struct memory_block *find_memory_block_hinted(struct mem_section *,
 							struct memory_block *);
 extern struct memory_block *find_memory_block(struct mem_section *);
+extern bool is_memblk_offline(unsigned long start, unsigned long size);
 #define CONFIG_MEM_BLOCK_SIZE	(PAGES_PER_SECTION<<PAGE_SHIFT)
 enum mem_add_context { BOOT, HOTPLUG };
 #endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
Index: linux-3.6/mm/memory_hotplug.c
===================================================================
--- linux-3.6.orig/mm/memory_hotplug.c	2012-10-04 14:31:08.000000000 +0900
+++ linux-3.6/mm/memory_hotplug.c	2012-10-04 14:58:22.449687986 +0900
@@ -1045,8 +1045,21 @@ int offline_memory(u64 start, u64 size)
 
 int remove_memory(int nid, u64 start, u64 size)
 {
-	/* It is not implemented yet*/
-	return 0;
+	int ret = 0;
+	lock_memory_hotplug();
+	/*
+	 * The memory might become online by other task, even if you offine it.
+	 * So we check whether the memory has been onlined or not.
+	 */
+	if (!is_memblk_offline(start, size)) {
+		pr_warn("memory removing [mem %#010llx-%#010llx] failed, "
+			"because the memmory range is online\n",
+			start, start + size);
+		ret = -EAGAIN;
+	}
+
+	unlock_memory_hotplug();
+	return ret;
 }
 EXPORT_SYMBOL_GPL(remove_memory);
 #else

^ permalink raw reply

* [PATCH 0/10] memory-hotplug: hot-remove physical memory
From: Yasuaki Ishimatsu @ 2012-10-05  2:20 UTC (permalink / raw)
  To: x86, linux-mm, linux-kernel, linuxppc-dev, linux-acpi, linux-s390,
	linux-sh, linux-ia64, cmetcalf, sparclinux
  Cc: len.brown, wency, isimatu.yasuaki, minchan.kim, kosaki.motohiro,
	rientjes, cl, akpm, liuj97

The patch-set was divided from following thread's patch-set.

https://lkml.org/lkml/2012/9/5/201

If you want to know the reason, please read following thread.

https://lkml.org/lkml/2012/10/2/83

The patch-set has only the function of kernel core side for physical
memory hot remove. So if you use the patch, please apply following
patches.

- bug fix for memory hot remove
  https://lkml.org/lkml/2012/9/27/39
  https://lkml.org/lkml/2012/10/2/83
  http://www.spinics.net/lists/linux-mm/msg42982.html
  
- acpi framework
  https://lkml.org/lkml/2012/10/3/126
  https://lkml.org/lkml/2012/10/3/641

The patches can free/remove the following things:

  - /sys/firmware/memmap/X/{end, start, type} : [PATCH 2/10]
  - mem_section and related sysfs files       : [PATCH 3-4/10]
  - memmap of sparse-vmemmap                  : [PATCH 5-7/10]
  - page table of removed memory              : [RFC PATCH 8/10]
  - node and related sysfs files              : [RFC PATCH 9-10/10]

* [PATCH 1/10] checks whether the memory can be removed or not.

If you find lack of function for physical memory hot-remove, please let me
know.

How to test this patchset?
1. apply this patchset and build the kernel. MEMORY_HOTPLUG, MEMORY_HOTREMOVE,
   ACPI_HOTPLUG_MEMORY must be selected.
2. load the module acpi_memhotplug
3. hotplug the memory device(it depends on your hardware)
   You will see the memory device under the directory /sys/bus/acpi/devices/.
   Its name is PNP0C80:XX.
4. online/offline pages provided by this memory device
   You can write online/offline to /sys/devices/system/memory/memoryX/state to
   online/offline pages provided by this memory device
5. hotremove the memory device
   You can hotremove the memory device by the hardware, or writing 1 to
   /sys/bus/acpi/devices/PNP0C80:XX/eject.

Note: if the memory provided by the memory device is used by the kernel, it
can't be offlined. It is not a bug.

Known problems:
1. memory can't be offlined when CONFIG_MEMCG is selected.
   For example: there is a memory device on node 1. The address range
   is [1G, 1.5G). You will find 4 new directories memory8, memory9, memory10,
   and memory11 under the directory /sys/devices/system/memory/.
   If CONFIG_MEMCG is selected, we will allocate memory to store page cgroup
   when we online pages. When we online memory8, the memory stored page cgroup
   is not provided by this memory device. But when we online memory9, the memory
   stored page cgroup may be provided by memory8. So we can't offline memory8
   now. We should offline the memory in the reversed order.
   When the memory device is hotremoved, we will auto offline memory provided
   by this memory device. But we don't know which memory is onlined first, so
   offlining memory may fail. In such case, you should offline the memory by
   hand before hotremoving the memory device.
2. hotremoving memory device may cause kernel panicked
   This bug will be fixed by Liu Jiang's patch:
   https://lkml.org/lkml/2012/7/3/1

^ permalink raw reply

* RE: [PATCH 5/5] rapidio: add destination ID allocation mechanism
From: Bounine, Alexandre @ 2012-10-04 20:39 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org
In-Reply-To: <20121003153625.39fd5af7.akpm@linux-foundation.org>

On Wed, October 03, 2012 6:36 PM
Andrew Morton <akpm@linux-foundation.org> wrote:
>=20
> On Wed,  3 Oct 2012 15:18:43 -0400
> Alexandre Bounine <alexandre.bounine@idt.com> wrote:
>=20
> > ...
> >
> > +static u16 rio_destid_alloc(struct rio_net *net)
> > +{
> > +	int destid;
> > +	struct rio_id_table *idtab =3D &net->destid_table;
> > +
> > +	spin_lock(&idtab->lock);
> > +	destid =3D find_next_zero_bit(idtab->table, idtab->max, idtab-
> >next);
> > +	if (destid >=3D idtab->max)
> > +		destid =3D find_first_zero_bit(idtab->table, idtab->max);
> > +
> > +	if (destid < idtab->max) {
> > +		idtab->next =3D destid + 1;
> > +		if (idtab->next >=3D idtab->max)
> > +			idtab->next =3D 0;
> > +		set_bit(destid, idtab->table);
> > +		destid +=3D idtab->start;
> > +	} else
> > +		destid =3D RIO_INVALID_DESTID;
> > +
> > +	spin_unlock(&idtab->lock);
> > +	return (u16)destid;
> > +}
>=20
> This is round-robin rather than the simpler first-fit, and this reader
> doesn't know why.  Suggest the addition of a code comment explaining
> this decision.

This is to make debugging easier. Having fresh new destID assigned to
a device after insertion helps to analyze switch routing table updates.
Yes, find-first is sufficient and better understandable (I had it in
early version).
I will switch to find-first scenario to make things clear.  =20

>=20
> > +/*
> > + * rio_destid_reserve - Reserve the specivied destID
> > + * net: RIO network
> > + * destid: destID to reserve
> > + *
> > + * Tries to reserve the specified destID.
> > + * Returns 0 if successfull.
> > + */
> > +static int rio_destid_reserve(struct rio_net *net, u16 destid)
> > +{
> > +	int oldbit;
> > +	struct rio_id_table *idtab =3D &net->destid_table;
> > +
> > +	destid -=3D idtab->start;
> > +	spin_lock(&idtab->lock);
> > +	oldbit =3D test_and_set_bit(destid, idtab->table);
> > +	spin_unlock(&idtab->lock);
> > +	return oldbit;
> > +}
> > +
> > +/*
> > + * rio_destid_free - free a previously allocated destID
> > + * net: RIO network
> > + * destid: destID to free
> > + *
> > + * Makes the specified destID available for use.
> > + */
> > +static void rio_destid_free(struct rio_net *net, u16 destid)
> > +{
> > +	struct rio_id_table *idtab =3D &net->destid_table;
> > +
> > +	destid -=3D idtab->start;
> > +	spin_lock(&idtab->lock);
> > +	clear_bit(destid, idtab->table);
> > +	spin_unlock(&idtab->lock);
> > +}
> > +
> > +/*
> > + * rio_destid_first - return first destID in use
> > + * net: RIO network
> > + */
> > +static u16 rio_destid_first(struct rio_net *net)
> > +{
> > +	int destid;
> > +	struct rio_id_table *idtab =3D &net->destid_table;
> > +
> > +	spin_lock(&idtab->lock);
> > +	destid =3D find_first_bit(idtab->table, idtab->max);
> > +	if (destid >=3D idtab->max)
> > +		destid =3D RIO_INVALID_DESTID;
> > +	else
> > +		destid +=3D idtab->start;
> > +	spin_unlock(&idtab->lock);
> > +	return (u16)destid;
> > +}
> > +
> > +/*
> > + * rio_destid_next - return next destID in use
> > + * net: RIO network
> > + * from: destination ID from which search shall continue
> > + */
>=20
> All these code comments look like kerneldoc, but they aren't.
> kerneldoc
> uses /** and identifiers have a leading `@'.  And that's OK - one
> doesn't *have* to use kerneldoc.  But a lot of
> drivers/rapidio/rio-scan.c is already using kerneldoc so the
> inconsistency is odd.

Idea here was that keeping static functions out of kerneldoc may
have sense and result in cleaner doc output. This was my first attempt
to take that path. Probably, kerneldoc adjustment patch for entire
file (or even all RapidIO files) would be more appropriate instead of
changing style half-way.
As you noticed, these comments are similar to kerneldoc - easy to get back
to old style. I will restore kerneldoc style for affected functions.=20

>=20
> >
> > ...
> >
> > -static struct rio_net __devinit *rio_alloc_net(struct rio_mport
> *port)
> > +static struct rio_net __devinit *rio_alloc_net(struct rio_mport
> *port,
> > +					       int do_enum, u16 start)
> >  {
> >  	struct rio_net *net;
> >
> >  	net =3D kzalloc(sizeof(struct rio_net), GFP_KERNEL);
> > +	if (net && do_enum) {
> > +		net->destid_table.table =3D kzalloc(
> > +			BITS_TO_LONGS(RIO_MAX_ROUTE_ENTRIES(port->sys_size))
> *
> > +			sizeof(long),
> > +			GFP_KERNEL);
>=20
> kcalloc() would be idiomatic here.

Agree. Will change.

>=20
> > +		if (net->destid_table.table =3D=3D NULL) {
> > +			pr_err("RIO: failed to allocate destID table\n");
> > +			kfree(net);
> > +			net =3D NULL;
> > +		} else {
> > +			net->destid_table.start =3D start;
> > +			net->destid_table.next =3D 0;
> > +			net->destid_table.max =3D
> > +					RIO_MAX_ROUTE_ENTRIES(port->sys_size);
> > +			spin_lock_init(&net->destid_table.lock);
> > +		}
> > +	}
> > +
> >
> > ...
> >

^ permalink raw reply

* Re: [git pull] Please pull powerpc.git merge branch
From: Benjamin Herrenschmidt @ 2012-10-04 20:14 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linuxppc-dev list, Linux Kernel list
In-Reply-To: <CA+55aFwf3XcC-SW5D6PouGCKqDRg7k7xbFHaPf-BBqRLa_-FBg@mail.gmail.com>

On Thu, 2012-10-04 at 09:02 -0700, Linus Torvalds wrote:
> Hmm. There's nothing there.
> 
> Did you mean for me to pull some branch/tag you didn't mention?

Heh, yeah, the mirrors hadn't updated yet so git request-pull didn't put
the branch name in. It's common but I usually fix it up by hand. Since I
was probably too tired for thinking straight, I forgot that and forgot
to put the proper branch name in the email subject as well... argh :-)

It's in my next branch. Mirrors should be good by now, it's at:

  git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git next

Sorry for the misshap.

Cheers,
Ben.

^ permalink raw reply

* Re: [git pull] Please pull powerpc.git merge branch
From: Benjamin Herrenschmidt @ 2012-10-04 20:10 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linuxppc-dev list, Linux Kernel list
In-Reply-To: <CA+55aFxbzeNG=sAQvPcE56rEpAbACqM04m2s73BzXVgK+PCnaQ@mail.gmail.com>

On Thu, 2012-10-04 at 09:00 -0700, Linus Torvalds wrote:
> So this happens if you have "reverse merges" (ie you've pulled my
> tree, or some other tree I've pulled), and there is no longer a single
> clear common point that you started from. In that case, there is no
> simple diff for the "what has changed since that original point", and
> to get the diff for the merge you actually have to do the merge and
> check the end result. git-request-pull doesn't do that, it just
> assumes it's the simple case of some single common point.

That was more/less my guess. Thanks.

> The fact that you haven't seen it until now just means that you've
> generally done a good job at keeping your powerpc tree "clean" from
> other trees, and containing only your own work. 

Heh, yeah I try to :-) In this specific case, this was a topic branch
from Bjorn which some pre-requisite patches to the generic PCI code that
Gavin did to allow us to get rid of some custom resource allocation
crap, so the "getting rid of" had a dependency on that topic branch.

Unfortunately, Bjorn had also based that branch on top of some larger
cleanup patch so I ended up pulling that as well from him, which tripped
the whole thing.

Cheers,
Ben.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox