https://www.kernel.org/doc/Documentation/memory-hotplug.txt

Oct 11 2007</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 内存的热插拔技术

&nbsp;&nbsp;&nbsp; 这个文档主要介绍内存的热插拔技术的使用以及该技术的当前情况。因为该技术当期人然处于开发阶段,所以这个的内容经常会发生变化。</span>

<span style="font-family: times new roman,times,serif;">1.介绍:

&nbsp;&nbsp;&nbsp;&nbsp; 1.1 内存热插拔的目的;</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 1.2 内存热插拔的几个阶段;</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 1.3上、下线操作的内存单元;</span>

<span style="font-family: times new roman,times,serif;">2.内核的配置;</span>

<span style="font-family: times new roman,times,serif;">3.内存热插拔的sysfs文件;</span>

<span style="font-family: times new roman,times,serif;">4.物理内存的热添加阶段;</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 4.1 硬件(固件)的支持;</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 4.2 手动通知内存热添加事件;</span>

<span style="font-family: times new roman,times,serif;">5 .逻辑内存的热添加阶段;</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 5.1逻辑内存的状态;</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 5.2怎样去上线逻辑内存;</span>

<span style="font-family: times new roman,times,serif;">6.逻辑内存的移除;</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 6.1逻辑内存的下线和ZONO_MOVABLE</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 6.2 怎样去下线逻辑内存;</span>

<span style="font-family: times new roman,times,serif;">7.物理内存的移除;</span>

<span style="font-family: times new roman,times,serif;">8.内存热插拔事件的通知;</span>

<span style="font-family: times new roman,times,serif;">9.今后的工作列表</span>

<span style="font-family: times new roman,times,serif;">Note(1): x86_64&#39;s has special implementation for memory hotplug.

This text does not describe it.

x86_64&#39;s 对内存热插拔功能有特殊实现。

本文不描述它。

Note(2): This text assumes that sysfs is mounted at /sys.

本文假定的sysfs安装在/ SYS。</span>

<span style="font-family: times new roman,times,serif;">一.介绍:</span>

<span style="font-family: times new roman,times,serif;">1.1 内存热插拔的目的:</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 内存热插拔允许使用者去增加或减少内存的大小。这样做通常出于两种目的:</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 第一种:改变内存的大小;</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 第二种:从物理上安装或移除DIMMs或NUMA(not uniform memory access)节点。这样时为了交换DIMMS或NUMA节点,降低电量的消耗。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 第一种主要应用于高度虚拟化环境之中。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 第二种主要应用于支持电源管理的硬件。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 设计内存热插拔就是为了以上两个目的。</span>

<span style="font-family: times new roman,times,serif;">1.2 内存热插拔的阶段:</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 内存热插拔分为两个阶段。&nbsp;</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1) 物理内存热插拔阶段。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2)逻辑内存热插拔阶段。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 第一个阶段目的是为了与硬件进行通信和构建或擦出热插拔内存需要的环境。基本上,对第二种目的来说这个阶段时必须的,</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; <span style="color: rgb(255, 0, 0);">当内存被热插拔时,内核会识别新的内存,创建新的内存管理表和对新内存进行操作的sysfs文件。</span></span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 如果固件支持操作系统中的新内存的连接通知,那么这个阶段会被自动的出发<span style="color: rgb(255, 0, 0);">。ACPI可以通知系统中有新的内存加入这个事件</span>。如果你的固件不支持的话,系统管理员可以使用&ldquo;探索&rdquo;操作。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 逻辑内存热插拔阶段是为了去改变内存的状态,使内存对使用者可用或不可用。通过这个阶段,使用者所看到的内存的大小发生了变化。当一段内存可用时,<span style="color: rgb(255, 0, 0);">内核把这段内存划分为许多可以自由使用的页。</span></span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 在这个文档中,逻辑内存热插拔阶段被描述为上线、下线online/offline。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 通过系统管理员对sysfs文件进行写操作,可以触发逻辑内存热插拔阶段。对这种热添加情况,在物理热插拔完成以后,逻辑热插拔阶段必须被执行通过手动操作。但是,如果你写了一个为内存热插拔的udev&#39;s hotplug scripts脚本的话,这些阶段可以被透明的执行。</span>

<span style="font-family: times new roman,times,serif;">(新内核会自动完成online过程)</span>

<span style="font-family: times new roman,times,serif;">1.3 上、下线操作的内存单元。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp; 内存热插拔使用稀疏内存模型(SPARSEMEM)。SPARSEMEM把整个内存划分为大小相同的块。每一块也被叫做一段。每一段的大小是多少取决与计算机的体系结构。例如,power架构中每一段的大小为16MB,ia64架构中每一段的大小为1GB。</span>

<span style="font-family: times new roman,times,serif;">内存部分 是由 一些称之为&ldquo;内存块&rdquo; 组合而成的,一个内存块的大小是与体系结构相关的, 内存块作为逻辑单元可以被执行上线/下线。一个内存块的默认大小是相同于内存段的大小,除非架构另外规定(<span style="color: rgb(255, 0, 0);">centos默认是128MB</span>)</span>

<span style="font-family: times new roman,times,serif;">对内存进行上下线操作是以内存段为单位的。&nbsp;&nbsp; 为了去知道内存段的大小,你可以去看看你系统中的这个文件:</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp; /sys/devices/system/memory/block_size_bytes 单位是字节。</span>

<span style="font-family: times new roman,times,serif;">2\. 内核的配置。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 为了使用内存热插拔功能,内核必须得按照下面的配置选项进行编译。</span>

<span style="font-family: times new roman,times,serif;">&nbsp; ---对所有内存热插拔:</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 内存模型---&gt; 稀疏内存(Sparse Memory)&nbsp;&nbsp; (CONFIG_SPARSEMEM)</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 允许内存热添加( CONFIG_MEMORY_HOTPLUG )</span>

<span style="font-family: times new roman,times,serif;">&nbsp; ---为了能移除内存,下面的选项是必须的</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 允许内存热移除(CONFIG_MEMORY_HOTREMOVE)</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 页迁移(CONFIG_MIGRATION)</span>

<span style="font-family: times new roman,times,serif;">&nbsp; ---对ACPI(Advanced Configuration And Power Interface)内存热插拔,下面的配置选项也是必须的:</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 内存热插拔(该选项在ACPI支持菜单下面)&nbsp;&nbsp;&nbsp; (CONFIG_ACPI_HOTPLUG_MEMORY)</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 这个选项可以是内核模块</span>

<span style="font-family: times new roman,times,serif;">&nbsp; ---作为一个相关的配置,如果你的计算机支持通过ACPI进行NUMA(Non Uniform Memory Access)节点热插拔,</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 那么下面的这个选项也是必须的。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; ACPI0004,PNP0A05 ,PNP0A06 Container Driver(在ACPI支持菜单下面 under ACPI Support Menu) (CONFIG_ACPI_CONTAINER)</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 这个选项也可能是个内核模块。</span>

<span style="font-family: times new roman,times,serif;">4\. 内存热插拔 sysfs文件</span>

<span style="font-family: times new roman,times,serif;">所有的内存段的设备信息都在sysfs文件里。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;<span style="color: rgb(255, 0, 0);"> 每个内存段的设备信息在/sys/devices/system/memory目录下按照 /sys/devices/system/memory/memoryXXX 形式存放着.(XXX是内存段的ID号)</span></span>

<span style="font-family: times new roman,times,serif;">sysfs目录涵盖涵盖所有的内存块,他要求当前所有的内存段都要在这个范围里,并不允许存在 memory holes。目前还没有办法确定是否存在一个memory hole,但一个的存在应该不影响到存储器块的热插拔能力。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 例如,假设一个内存段的大小为1GB. 一个起始地址为0X1 0000 0000的内存设备在 /sys/devices/system/memory目录下面的文件是 :/sys/devices/system/memory/memory4( 0X1 0000 0000 / 1GB = 4). 这个设备覆盖的地址范围</span>

<span style="font-family: times new roman,times,serif;">[ 0X1 0000 0000 ---- 0X1 4000 0000)</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 在每个内存段设备文件下面,你可以看到4个文件:</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; /sys/devices/system/memory/memoryXXX/phys_index</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; /sys/devices/system/memory/memoryXXX/phys_device</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; /sys/devices/system/memory/memoryXXX/state</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp; /sys/devices/system/memory/memoryXXX/removable</span>

<span style="font-family: times new roman,times,serif;">&nbsp; &lsquo;phys_index&rsquo; : 只读文件并且包含内存段的ID号,像XXX.</span>

<span style="font-family: times new roman,times,serif;">&nbsp; &lsquo;state&rsquo;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; : 可读写;</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用于读时: 包含内存的上下线状态;</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 用于写时: 使用者可以指定&ldquo;online&rdquo;, &ldquo;offline&rdquo; 命令.</span>

<span style="font-family: times new roman,times,serif;">&nbsp; &lsquo;phys_device&#39; : 只读 : 被设计用来显示物理内存的设备名.</span>

<span style="font-family: times new roman,times,serif;">&nbsp; &lsquo;removable&#39;&nbsp;&nbsp; : 只读 : 包含一个整数值,这个整数值表示内存段是否可移除.</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 整数1,代表这个内存段是可移除。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 整数0,代表这个内存段是不可移除的。

&#39;valid_zones&#39;&nbsp;&nbsp;&nbsp;&nbsp; : read-only: designed to show which zones this memory block

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; can be onlined to.

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; The first column shows it&#39;s default zone.

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;memory6/valid_zones: Normal Movable&quot; shows this memoryblock

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; can be onlined to ZONE_NORMAL by default and to ZONE_MOVABLE

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; by online_movable.

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;memory7/valid_zones: Movable Normal&quot; shows this memoryblock

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; can be onlined to ZONE_MOVABLE by default and to ZONE_NORMAL

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; by online_kernel.</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 注意:在物理内存热插拔阶段之后,这些目录/文件才会出现。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 如果CONFIG_NUMA选项可用,可以通过在 /sys/devices/system/node/node* directories 下面的符号链接来访问/sys/devices/system/memory/memoryXXX 内存段目录。</span>

<span style="font-family: times new roman,times,serif;">例如 /sys/devices/system/node/node0/memory9----&gt;../../memory/memory9</span>

<span style="font-family: times new roman,times,serif;">4\. 物理内存热添加阶段</span>

<span style="font-family: times new roman,times,serif;">4.1 硬件(固件)支持</span>

<span style="font-family: times new roman,times,serif;">在x86_64/ia64 平台上,ACPI支持内存热插拔。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 一般来说,支持内存热插拔的固件(ACPI)定义了_HID &ldquo;PNP0C80&rdquo; 内存类对象。当PNP0C80接受到一个通知时,Linux&#39;s ACPI handler(Linux ACPI处理程序/函数)把热添加内存加入到系统,并且调用一个 hotplug udev scripts.</span>

<span style="font-family: times new roman,times,serif;">这个动作将会被自动完成。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 但是内存热插拔脚本通常不会被包含在 udev 包中。你可能必须自己去写这些脚本或者手动的上下线内存。这个文档也介绍了怎样上线内存和怎样下线内存。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 如果固件支持NUMA-node热插拔,并且定义一个 _HID &ldquo;ACPI0004&rdquo; , &ldquo;PNP0A05&rdquo;, 或&ldquo;PNP0A06&rdquo;对象。当对象接受到一个通知时,ACPI handler对定义在它里面的所有对象调用 hotplug 代码。如果找到了内存设备,memory hotplug代码将会被调用。</span>

<span style="font-family: times new roman,times,serif;">4.2 手动通知内存热添加事件。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 在一些环境中,尤其是虚拟环境,固件将不会向内核通知内存添加事件。对于这些环境,可以使用&ldquo;探索&rdquo;接口(probe interface)来通知内核。 探索接口依赖于 CONFIG_ARCH_MEMORY_PROBE选项并且可以被配置在 powerpc, sh,如果x86支持热插拔,那也是有ACPI通知办理。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 探索接口位于: /sys/devices/system/memory/probe</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 你可以通过 % echo start_address_of_new_memory &gt; /sys/devices/system/memory/probe 来告诉内核新的物理内存的地址。</span>

<span style="font-family: times new roman,times,serif;">那么,[ start_address_of_new_memory , start_address_of_new_memory + section )(新的内存的起始地址, 新的内存的起始地址 + 内存段的大小) 内存范围就会被热添加。在这种情况下,热插拔脚本并不会被调用(the current implementation)。</span>

<span style="font-family: times new roman,times,serif;">5.逻辑内存热添加阶段。</span>

<span style="font-family: times new roman,times,serif;">5.1 内存的状态</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 通过 % cat&nbsp; /sys/devices/system/memory/memoryXXX/state 文件去了解内存段的上下线 (online/offline) 的状态。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 如果内存段处于online state, 你将看到&ldquo;online&rdquo;;</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 如果内存段处于offline state, 你将看到 &ldquo;offline&rdquo;;</span>

<span style="font-family: times new roman,times,serif;">5.2 怎么去上线online内存</span>

<span style="font-family: times new roman,times,serif;">当内存被热添加,内核根据策略来决定是否为&ldquo;在线&rdquo;,可从&ldquo;auto_online_blocks&rdquo;文件中读出它的策略:

# cat /sys/devices/system/memory/auto_online_blocks</span>

<span style="font-family: times new roman,times,serif;">默认值依赖于CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE内核配置 选项。如果禁用默认为&ldquo;脱机offline&rdquo;,这意味着新被热添加的内存并不是处于ready-to-use的状态,</span>

<span style="font-family: times new roman,times,serif;">你必须手动将这些新被热添加的内存块 设置成&ldquo;在线online&rdquo;。自动在线可以被要求写成&ldquo;online&rdquo;在auto_online_blocks的文件里:</span>

<span style="font-family: times new roman,times,serif;">&nbsp; echo online &gt; /sys/devices/system/memory/auto_online_blocks</span>

<span style="font-family: times new roman,times,serif;">这个设置是个全局性的策略,将影响随后所有热插拔的内存块。当前离线 offline块保持自己的状态。</span>

<span style="font-family: times new roman,times,serif;">有个可能,在某些情况下,一些内存块被加入后,会将无法联机。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;用户空间工具可以检查它们的&ldquo;state&rdquo;文件 (/sys/devices/system/memory/memoryXXX/state),可以尝试手动online它们</span>

<span style="font-family: times new roman,times,serif;">如果没有要求自动onlining,或者某些内存块是脱机的,就可以通过写它们的&ldquo;state&rdquo;文件来改变单个内存块的状态</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; % <span style="color: rgb(255, 0, 0);">echo&nbsp; online &gt; /sys/devices/system/memory/memoryXXX/state</span>。 之后,memoryXXX内存段的状态将是&ldquo;online&rdquo;</span>

<span style="font-family: times new roman,times,serif;">这些onlining不会改变目标内存块的区域类型ZONE type,</span>

<span style="font-family: times new roman,times,serif;">如果内存块是在ZONE_NORMAL,你可以把它改到ZONE_MOVABLE:</span>

<span style="font-family: times new roman,times,serif;">% echo online_movable &gt; /sys/devices/system/memory/memoryXXX/state

(注:当前的限制:这些内存块必须邻接ZONE_MOVABLE)</span>

<span style="font-family: times new roman,times,serif;">同时如果内存块是在ZONE_MOVABLE,你可以把它改到ZONE_NORMAL:

% echo online_kernel &gt; /sys/devices/system/memory/memoryXXX/state

(注:当前的限制:这些内存块必须邻接ZONE_MOVABLE)</span>

<span style="font-family: times new roman,times,serif;">之后,memoryXXX内存段的状态将是&ldquo;online&rdquo; 并且可用的内存大小也会增加。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;目前,新添加的内存将会被添加到ZONE_NORMAL(for powerpc ZONE_DMA)。这可能会在将来可以改变。</span>

<span style="font-family: times new roman,times,serif;">6\. 逻辑内存的移除</span>

<span style="font-family: times new roman,times,serif;">6.1 逻辑内存的下线和ZONE_MOVABLE。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 内存下线比内存上线更加的复杂。因为内存下线必须使整个内存段都不未使用,如果内存段中包含有仍未释放的内存的换,内存下线操作就可能失败。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 一般来说,内存下线使用2种技术。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 第一种技术,回收(reclaim)并且释放在内存段中的所有内存。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 第二种技术,迁移在内存段中的所有的页。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 在目前的实现,Linux的内存下线使用第二种技术,通过页迁移来释放内存段中的所有的页。但是并不是所有的页都是可迁移的。在当前的Linux下,可迁移的页是匿名页(anonymous pages)和页缓存。由于通过迁移页来下线一个内存段,所以内核必须确保内存段中只包含可迁移的页。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 现在,制作一个由可迁移的页组成的内存段的引导选项已经可以用了。通过指定&ldquo;kernelcore= &rdquo; 或者&ldquo;movablecore=&rdquo; 引导选项,你可以创建一个ZONE_MOVABLE区域,这个区域被用于可移动的页。(See also Documentation/kernel-parameters.txt)</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 假设在引导时,系统的内存大小为&ldquo;TOTAL&rdquo;,这个引导选项按照如下方式创建ZONE_MOVABLE。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.当使用kernelcore=YYYY引导选项时,为可移动页的内存大小为: TOTAL &ndash; YYYY,而不是 YYYY。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.当使用movablecore= ZZZZ引导选项时,为可移动页的内存大小为: ZZZZ ,而不是TOTAL &ndash; ZZZZ。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 注意:不幸的是,没有任何信息去显示那个内存段是属于ZONE_MOVABLE。This is TBD</span>

<span style="font-family: times new roman,times,serif;">6.2 怎样去下线一个内存段</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; 你可以通过使用与内存段上线相同的系统文件去下线一个内存段。</span>

<span style="font-family: times new roman,times,serif;">% echo offline &gt; /sys/devices/system/memory/memoryXXX/state 。</span>

<span style="font-family: times new roman,times,serif;">如果下线操作成功,这个内存段的状态将会被改变为&ldquo;offline&rdquo;。如果下线操作失败,内核将会返回一些错误值(像:-EBUSY)。即使一个内存段不属于ZONE_MOVABLE,你也可以尝试去下线它。</span>

<span style="font-family: times new roman,times,serif;">如果它中没有不可移动的内存的话,你将会成功。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; 处于ZONE_MOVABLE的内存段被认为是能很容易下线的。但是如果这样的内存段处于繁忙的状态下,对它们进行下线,系统会返回-EBUSY。即使一个内存段由于-EBUSY而不能下线,你可以重试,并且有可能会成功与有可能失败。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp; Consideration:</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp; 内存热插拔的设计方向是为了使内存下线的可能性更高,确保在任何状况下都可以拔下内存。但是它需要更好的工作。在一些状况下返回-EBUSY是非常好的,因为使用者可以自己去决定是否需要再次的重试。目前,内存下线代码会每120seconds去做重试统计。</span>

<span style="font-family: times new roman,times,serif;">7.物理内存的移除</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp; 需要更好的实现但是...</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp; --- 操作系统去通知固件硬件移除工作完成。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp; ---如果不需要的话,避免移除。</span>

<span style="font-family: times new roman,times,serif;">8.内存热插拔事件通知者</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp; 内存热插拔有事件通知者(notifer)。有6中类型的通知。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp; MEMORY_GOING_ONLINE</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp; 在新的内存变为可用之前产生,目的是为了能准备子系统去处理内存。页分配器仍然不能从新的内存中分配页。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp; MEMORY_CANCEL_ONLINE</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp; 如果MEMORY_GOING_ONLINE失败,产生。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp; MEMORY_ONLINE</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp; 当内存已经成功的完成上线时产生。回调函数(callback)可以从新的内存中分配页。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp; MEMORY_GOING_OFFLINE</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp; 开始运行内存下线进程的时候产生。不再在可能再从内存中分配页了,但是将被下线的内存段中仍然有一些内存在使用。回调函数可以去释放已知的内存到子系统。这个子系统来自于指示的内存段。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp; MEMORY_CANCEL_OFFLLINE</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp; 如果MEMORY_GOING_OFFLINE失败,产生。来自于我们试图去下线的内存段的内存再一次可用了。</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp; MEMORY_OFFLINE</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp; 内存下线完成以后产生。</span>

<span style="font-family: times new roman,times,serif;">通过hotplug_memory_notifier( callback_func,&nbsp; priority ) 可以注册一个回调程序。</span>

<span style="font-family: times new roman,times,serif;">回调函数的第二个参数是以上的六种类型。回调函数的第三个参数是一个指向struct memory_notify的指针。</span>

<span style="font-family: times new roman,times,serif;">&nbsp; Struct memory_notify</span>

<span style="font-family: times new roman,times,serif;">&nbsp; {</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; unsigned long&nbsp; start_pfn; // 是上下线内存段的start_pfn</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; unsigned long nr_pages;&nbsp; // 是上下线内存段的页数</span>

<span style="font-family: times new roman,times,serif;">&nbsp;&nbsp;&nbsp;&nbsp; int status_change_nid;</span>

<span style="font-family: times new roman,times,serif;">&nbsp; }</span>

<span style="font-family: times new roman,times,serif;">&nbsp; 当节点掩码的N_HIGH_MEMORY是设置/清空, status_change_nid是被设置节点的ID。这意味着一个新的节点通过上线获取了一个新的内存,并且一个节点失去了所有的内存。如果,status_change_nid 是 -1,那么节点掩码的状态不能被改变。如果status_change_nid &gt;= 0,回调函数将可以为这个节点创建/抛弃结构体,如果需要的话。</span>

<span style="font-family: times new roman,times,serif;">9\. Future Work

--------------

&nbsp; - allowing memory hot-add to ZONE_MOVABLE. maybe we need some switch like&nbsp; sysctl or new control file.

&nbsp; - showing memory block and physical device relationship.

&nbsp; - test and make it better memory offlining.

&nbsp; - support HugeTLB page migration and offlining.

&nbsp; - memmap removing at memory offline.

&nbsp; - physical remove memory.</span>

<span style="font-family: times new roman,times,serif;">参考: [http://weiguozhihui.blog.51cto.com/3060615/1568258](http://weiguozhihui.blog.51cto.com/3060615/1568258)</span>