cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cpu_hotplug.rst (14950B)


      1.. include:: ../disclaimer-zh_CN.rst
      2
      3:Original: Documentation/core-api/cpu_hotplug.rst
      4:翻译:
      5
      6 司延腾 Yanteng Si <siyanteng@loongson.cn>
      7
      8:校译:
      9
     10 吴想成 Wu XiangCheng <bobwxc@email.cn>
     11
     12.. _cn_core_api_cpu_hotplug:
     13
     14=================
     15内核中的CPU热拔插
     16=================
     17
     18:时间: 2016年12月
     19:作者: Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
     20          Rusty Russell <rusty@rustcorp.com.au>,
     21          Srivatsa Vaddagiri <vatsa@in.ibm.com>,
     22          Ashok Raj <ashok.raj@intel.com>,
     23          Joel Schopp <jschopp@austin.ibm.com>
     24
     25简介
     26====
     27
     28现代系统架构的演进已经在处理器中引入了先进的错误报告和纠正能力。有一些OEM也支
     29持可热拔插的NUMA(Non Uniform Memory Access,非统一内存访问)硬件,其中物理
     30节点的插入和移除需要支持CPU热插拔。
     31
     32这样的进步要求内核可用的CPU被移除,要么是出于配置的原因,要么是出于RAS的目的,
     33以保持一个不需要的CPU不在系统执行路径。因此需要在Linux内核中支持CPU热拔插。
     34
     35CPU热拔插支持的一个更新颖的用途是它在SMP的暂停恢复支持中的应用。双核和超线程支
     36持使得即使是笔记本电脑也能运行不支持这些方法的SMP内核。
     37
     38
     39命令行开关
     40==========
     41
     42``maxcpus=n``
     43  限制启动时的CPU为 *n* 个。例如,如果你有四个CPU,使用 ``maxcpus=2`` 将只能启
     44  动两个。你可以选择稍后让其他CPU上线。
     45
     46``nr_cpus=n``
     47  限制内核将支持的CPU总量。如果这里提供的数量低于实际可用的CPU数量,那么其他CPU
     48  以后就不能上线了。
     49
     50``additional_cpus=n``
     51  使用它来限制可热插拔的CPU。该选项设置
     52  ``cpu_possible_mask = cpu_present_mask + additional_cpus``
     53
     54  这个选项只限于IA64架构。
     55
     56``possible_cpus=n``
     57  这个选项设置 ``cpu_possible_mask`` 中的 ``possible_cpus`` 位。
     58
     59  这个选项只限于X86和S390架构。
     60
     61``cpu0_hotplug``
     62  允许关闭CPU0。
     63
     64  这个选项只限于X86架构。
     65
     66CPU位图
     67=======
     68
     69``cpu_possible_mask``
     70  系统中可能可用CPU的位图。这是用来为per_cpu变量分配一些启动时的内存,这些变量
     71  不会随着CPU的可用或移除而增加/减少。一旦在启动时的发现阶段被设置,该映射就是静态
     72  的,也就是说,任何时候都不会增加或删除任何位。根据你的系统需求提前准确地调整它
     73  可以节省一些启动时的内存。
     74
     75``cpu_online_mask``
     76  当前在线的所有CPU的位图。在一个CPU可用于内核调度并准备接收设备的中断后,它被
     77  设置在 ``__cpu_up()`` 中。当使用 ``__cpu_disable()`` 关闭一个CPU时,它被清
     78  空,在此之前,所有的操作系统服务包括中断都被迁移到另一个目标CPU。
     79
     80``cpu_present_mask``
     81  系统中当前存在的CPU的位图。它们并非全部在线。当物理热拔插被相关的子系统
     82  (如ACPI)处理时,可以改变和添加新的位或从位图中删除,这取决于事件是
     83  hot-add/hot-remove。目前还没有定死规定。典型的用法是在启动时启动拓扑结构,这时
     84  热插拔被禁用。
     85
     86你真的不需要操作任何系统的CPU映射。在大多数情况下,它们应该是只读的。当设置每个
     87CPU资源时,几乎总是使用 ``cpu_possible_mask`` 或 ``for_each_possible_cpu()``
     88来进行迭代。宏 ``for_each_cpu()`` 可以用来迭代一个自定义的CPU掩码。
     89
     90不要使用 ``cpumask_t`` 以外的任何东西来表示CPU的位图。
     91
     92
     93使用CPU热拔插
     94=============
     95
     96内核选项 *CONFIG_HOTPLUG_CPU* 需要被启用。它目前可用于多种架构,包括ARM、MIPS、
     97PowerPC和X86。配置是通过sysfs接口完成的::
     98
     99 $ ls -lh /sys/devices/system/cpu
    100 total 0
    101 drwxr-xr-x  9 root root    0 Dec 21 16:33 cpu0
    102 drwxr-xr-x  9 root root    0 Dec 21 16:33 cpu1
    103 drwxr-xr-x  9 root root    0 Dec 21 16:33 cpu2
    104 drwxr-xr-x  9 root root    0 Dec 21 16:33 cpu3
    105 drwxr-xr-x  9 root root    0 Dec 21 16:33 cpu4
    106 drwxr-xr-x  9 root root    0 Dec 21 16:33 cpu5
    107 drwxr-xr-x  9 root root    0 Dec 21 16:33 cpu6
    108 drwxr-xr-x  9 root root    0 Dec 21 16:33 cpu7
    109 drwxr-xr-x  2 root root    0 Dec 21 16:33 hotplug
    110 -r--r--r--  1 root root 4.0K Dec 21 16:33 offline
    111 -r--r--r--  1 root root 4.0K Dec 21 16:33 online
    112 -r--r--r--  1 root root 4.0K Dec 21 16:33 possible
    113 -r--r--r--  1 root root 4.0K Dec 21 16:33 present
    114
    115文件 *offline* 、 *online* 、*possible* 、*present* 代表CPU掩码。每个CPU文件
    116夹包含一个 *online* 文件,控制逻辑上的开(1)和关(0)状态。要在逻辑上关闭CPU4::
    117
    118 $ echo 0 > /sys/devices/system/cpu/cpu4/online
    119  smpboot: CPU 4 is now offline
    120
    121一旦CPU被关闭,它将从 */proc/interrupts* 、*/proc/cpuinfo* 中被删除,也不应该
    122被 *top* 命令显示出来。要让CPU4重新上线::
    123
    124 $ echo 1 > /sys/devices/system/cpu/cpu4/online
    125 smpboot: Booting Node 0 Processor 4 APIC 0x1
    126
    127CPU又可以使用了。这应该对所有的CPU都有效。CPU0通常比较特殊,被排除在CPU热拔插之外。
    128在X86上,内核选项 *CONFIG_BOOTPARAM_HOTPLUG_CPU0* 必须被启用,以便能够关闭CPU0。
    129或者,可以使用内核命令选项 *cpu0_hotplug* 。CPU0的一些已知的依赖性:
    130
    131* 从休眠/暂停中恢复。如果CPU0处于离线状态,休眠/暂停将失败。
    132* PIC中断。如果检测到PIC中断,CPU0就不能被移除。
    133
    134如果你发现CPU0上有任何依赖性,请告知Fenghua Yu <fenghua.yu@intel.com>。
    135
    136CPU的热拔插协作
    137===============
    138
    139下线情况
    140--------
    141
    142一旦CPU被逻辑关闭,注册的热插拔状态的清除回调将被调用,从 ``CPUHP_ONLINE`` 开始,在
    143``CPUHP_OFFLINE`` 状态结束。这包括:
    144
    145* 如果任务因暂停操作而被冻结,那么 *cpuhp_tasks_frozen* 将被设置为true。
    146
    147* 所有进程都会从这个将要离线的CPU迁移到新的CPU上。新的CPU是从每个进程的当前cpuset中
    148  选择的,它可能是所有在线CPU的一个子集。
    149
    150* 所有针对这个CPU的中断都被迁移到新的CPU上。
    151
    152* 计时器也会被迁移到新的CPU上。
    153
    154* 一旦所有的服务被迁移,内核会调用一个特定的例程 ``__cpu_disable()`` 来进行特定的清
    155  理。
    156
    157使用热插拔API
    158-------------
    159
    160一旦一个CPU下线或上线,就有可能收到通知。这对某些需要根据可用CPU数量执行某种设置或清
    161理功能的驱动程序来说可能很重要::
    162
    163  #include <linux/cpuhotplug.h>
    164
    165  ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "X/Y:online",
    166                          Y_online, Y_prepare_down);
    167
    168*X* 是子系统, *Y* 是特定的驱动程序。 *Y_online* 回调将在所有在线CPU的注册过程中被调用。
    169如果在线回调期间发生错误, *Y_prepare_down*  回调将在所有之前调用过在线回调的CPU上调
    170用。注册完成后,一旦有CPU上线, *Y_online* 回调将被调用,当CPU关闭时, *Y_prepare_down*
    171将被调用。所有之前在 *Y_online* 中分配的资源都应该在 *Y_prepare_down* 中释放。如果在
    172注册过程中发生错误,返回值 *ret* 为负值。否则会返回一个正值,其中包含动态分配状态
    173( *CPUHP_AP_ONLINE_DYN* )的分配热拔插。对于预定义的状态,它将返回0。
    174
    175该回调可以通过调用 ``cpuhp_remove_state()`` 来删除。如果是动态分配的状态
    176( *CPUHP_AP_ONLINE_DYN* ),则使用返回的状态。在移除热插拔状态的过程中,将调用拆解回调。
    177
    178多个实例
    179~~~~~~~~
    180
    181如果一个驱动程序有多个实例,并且每个实例都需要独立执行回调,那么很可能应该使用
    182``multi-state`` 。首先需要注册一个多状态的状态::
    183
    184  ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "X/Y:online,
    185                                Y_online, Y_prepare_down);
    186  Y_hp_online = ret;
    187
    188``cpuhp_setup_state_multi()`` 的行为与 ``cpuhp_setup_state()`` 类似,只是它
    189为多状态准备了回调,但不调用回调。这是一个一次性的设置。
    190一旦分配了一个新的实例,你需要注册这个新实例::
    191
    192  ret = cpuhp_state_add_instance(Y_hp_online, &d->node);
    193
    194这个函数将把这个实例添加到你先前分配的 ``Y_hp_online`` 状态,并在所有在线的
    195CPU上调用先前注册的回调( ``Y_online`` )。 *node* 元素是你的每个实例数据结构
    196中的一个 ``struct hlist_node`` 成员。
    197
    198在移除该实例时::
    199
    200  cpuhp_state_remove_instance(Y_hp_online, &d->node)
    201
    202应该被调用,这将在所有在线CPU上调用拆分回调。
    203
    204手动设置
    205~~~~~~~~
    206
    207通常情况下,在注册或移除状态时调用setup和teamdown回调是很方便的,因为通常在CPU上线
    208(下线)和驱动的初始设置(关闭)时需要执行该操作。然而,每个注册和删除功能也有一个
    209_nocalls的后缀,如果不希望调用回调,则不调用所提供的回调。在手动设置(或关闭)期间,
    210应该使用 ``get_online_cpus()`` 和 ``put_online_cpus()`` 函数来抑制CPU热插拔操作。
    211
    212
    213事件的顺序
    214----------
    215
    216热插拔状态被定义在 ``include/linux/cpuhotplug.h``:
    217
    218* ``CPUHP_OFFLINE`` ... ``CPUHP_AP_OFFLINE`` 状态是在CPU启动前调用的。
    219
    220* ``CPUHP_AP_OFFLINE`` ... ``CPUHP_AP_ONLINE`` 状态是在CPU被启动后被调用的。
    221  中断是关闭的,调度程序还没有在这个CPU上活动。从 ``CPUHP_AP_OFFLINE`` 开始,
    222  回调被调用到目标CPU上。
    223
    224* ``CPUHP_AP_ONLINE_DYN`` 和 ``CPUHP_AP_ONLINE_DYN_END`` 之间的状态被保留
    225  给动态分配。
    226
    227* 这些状态在CPU关闭时以相反的顺序调用,从 ``CPUHP_ONLINE`` 开始,在 ``CPUHP_OFFLINE``
    228  停止。这里的回调是在将被关闭的CPU上调用的,直到 ``CPUHP_AP_OFFLINE`` 。
    229
    230通过 ``CPUHP_AP_ONLINE_DYN`` 动态分配的状态通常已经足够了。然而,如果在启动或关闭
    231期间需要更早的调用,那么应该获得一个显式状态。如果热拔插事件需要相对于另一个热拔插事
    232件的特定排序,也可能需要一个显式状态。
    233
    234测试热拔插状态
    235==============
    236
    237验证自定义状态是否按预期工作的一个方法是关闭一个CPU,然后再把它上线。也可以把CPU放到某
    238些状态(例如 ``CPUHP_AP_ONLINE`` ),然后再回到 ``CPUHP_ONLINE`` 。这将模拟在
    239``CPUHP_AP_ONLINE`` 之后的一个状态出现错误,从而导致回滚到在线状态。
    240
    241所有注册的状态都被列举在 ``/sys/devices/system/cpu/hotplug/states`` ::
    242
    243 $ tail /sys/devices/system/cpu/hotplug/states
    244 138: mm/vmscan:online
    245 139: mm/vmstat:online
    246 140: lib/percpu_cnt:online
    247 141: acpi/cpu-drv:online
    248 142: base/cacheinfo:online
    249 143: virtio/net:online
    250 144: x86/mce:online
    251 145: printk:online
    252 168: sched:active
    253 169: online
    254
    255要将CPU4回滚到 ``lib/percpu_cnt:online`` ,再回到在线状态,只需发出::
    256
    257  $ cat /sys/devices/system/cpu/cpu4/hotplug/state
    258  169
    259  $ echo 140 > /sys/devices/system/cpu/cpu4/hotplug/target
    260  $ cat /sys/devices/system/cpu/cpu4/hotplug/state
    261  140
    262
    263需要注意的是,状态140的清除回调已经被调用。现在重新上线::
    264
    265  $ echo 169 > /sys/devices/system/cpu/cpu4/hotplug/target
    266  $ cat /sys/devices/system/cpu/cpu4/hotplug/state
    267  169
    268
    269启用追踪事件后,单个步骤也是可见的::
    270
    271  #  TASK-PID   CPU#    TIMESTAMP  FUNCTION
    272  #     | |       |        |         |
    273      bash-394  [001]  22.976: cpuhp_enter: cpu: 0004 target: 140 step: 169 (cpuhp_kick_ap_work)
    274   cpuhp/4-31   [004]  22.977: cpuhp_enter: cpu: 0004 target: 140 step: 168 (sched_cpu_deactivate)
    275   cpuhp/4-31   [004]  22.990: cpuhp_exit:  cpu: 0004  state: 168 step: 168 ret: 0
    276   cpuhp/4-31   [004]  22.991: cpuhp_enter: cpu: 0004 target: 140 step: 144 (mce_cpu_pre_down)
    277   cpuhp/4-31   [004]  22.992: cpuhp_exit:  cpu: 0004  state: 144 step: 144 ret: 0
    278   cpuhp/4-31   [004]  22.993: cpuhp_multi_enter: cpu: 0004 target: 140 step: 143 (virtnet_cpu_down_prep)
    279   cpuhp/4-31   [004]  22.994: cpuhp_exit:  cpu: 0004  state: 143 step: 143 ret: 0
    280   cpuhp/4-31   [004]  22.995: cpuhp_enter: cpu: 0004 target: 140 step: 142 (cacheinfo_cpu_pre_down)
    281   cpuhp/4-31   [004]  22.996: cpuhp_exit:  cpu: 0004  state: 142 step: 142 ret: 0
    282      bash-394  [001]  22.997: cpuhp_exit:  cpu: 0004  state: 140 step: 169 ret: 0
    283      bash-394  [005]  95.540: cpuhp_enter: cpu: 0004 target: 169 step: 140 (cpuhp_kick_ap_work)
    284   cpuhp/4-31   [004]  95.541: cpuhp_enter: cpu: 0004 target: 169 step: 141 (acpi_soft_cpu_online)
    285   cpuhp/4-31   [004]  95.542: cpuhp_exit:  cpu: 0004  state: 141 step: 141 ret: 0
    286   cpuhp/4-31   [004]  95.543: cpuhp_enter: cpu: 0004 target: 169 step: 142 (cacheinfo_cpu_online)
    287   cpuhp/4-31   [004]  95.544: cpuhp_exit:  cpu: 0004  state: 142 step: 142 ret: 0
    288   cpuhp/4-31   [004]  95.545: cpuhp_multi_enter: cpu: 0004 target: 169 step: 143 (virtnet_cpu_online)
    289   cpuhp/4-31   [004]  95.546: cpuhp_exit:  cpu: 0004  state: 143 step: 143 ret: 0
    290   cpuhp/4-31   [004]  95.547: cpuhp_enter: cpu: 0004 target: 169 step: 144 (mce_cpu_online)
    291   cpuhp/4-31   [004]  95.548: cpuhp_exit:  cpu: 0004  state: 144 step: 144 ret: 0
    292   cpuhp/4-31   [004]  95.549: cpuhp_enter: cpu: 0004 target: 169 step: 145 (console_cpu_notify)
    293   cpuhp/4-31   [004]  95.550: cpuhp_exit:  cpu: 0004  state: 145 step: 145 ret: 0
    294   cpuhp/4-31   [004]  95.551: cpuhp_enter: cpu: 0004 target: 169 step: 168 (sched_cpu_activate)
    295   cpuhp/4-31   [004]  95.552: cpuhp_exit:  cpu: 0004  state: 168 step: 168 ret: 0
    296      bash-394  [005]  95.553: cpuhp_exit:  cpu: 0004  state: 169 step: 140 ret: 0
    297
    298可以看到,CPU4一直下降到时间戳22.996,然后又上升到95.552。所有被调用的回调,
    299包括它们的返回代码都可以在跟踪中看到。
    300
    301架构的要求
    302==========
    303
    304需要具备以下功能和配置:
    305
    306``CONFIG_HOTPLUG_CPU``
    307  这个配置项需要在Kconfig中启用
    308
    309``__cpu_up()``
    310  调出一个cpu的架构接口
    311
    312``__cpu_disable()``
    313  关闭CPU的架构接口,在此程序返回后,内核不能再处理任何中断。这包括定时器的关闭。
    314
    315``__cpu_die()``
    316  这实际上是为了确保CPU的死亡。实际上,看看其他架构中实现CPU热拔插的一些示例代
    317  码。对于那个特定的架构,处理器被从 ``idle()`` 循环中拿下来。 ``__cpu_die()``
    318  通常会等待一些per_cpu状态的设置,以确保处理器的死亡例程被调用来保持活跃。
    319
    320用户空间通知
    321============
    322
    323在CPU成功上线或下线后,udev事件被发送。一个udev规则,比如::
    324
    325  SUBSYSTEM=="cpu", DRIVERS=="processor", DEVPATH=="/devices/system/cpu/*", RUN+="the_hotplug_receiver.sh"
    326
    327将接收所有事件。一个像这样的脚本::
    328
    329  #!/bin/sh
    330
    331  if [ "${ACTION}" = "offline" ]
    332  then
    333      echo "CPU ${DEVPATH##*/} offline"
    334
    335  elif [ "${ACTION}" = "online" ]
    336  then
    337      echo "CPU ${DEVPATH##*/} online"
    338
    339  fi
    340
    341可以进一步处理该事件。
    342
    343内核内联文档参考
    344================
    345
    346该API在以下内核代码中:
    347
    348include/linux/cpuhotplug.h