"sphinx.addnodesdocument)}( rawsourcechildren]( translations LanguagesNode)}(hhh](h pending_xref)}(hhh]docutils.nodesTextEnglish}parenthsba attributes}(ids]classes]names]dupnames]backrefs] refdomainstdreftypedoc reftarget/core-api/cpu_hotplugmodnameN classnameN refexplicitutagnamehhh ubh)}(hhh]hChinese (Traditional)}hh2sbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget(/translations/zh_TW/core-api/cpu_hotplugmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hItalian}hhFsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget(/translations/it_IT/core-api/cpu_hotplugmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hJapanese}hhZsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget(/translations/ja_JP/core-api/cpu_hotplugmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hKorean}hhnsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget(/translations/ko_KR/core-api/cpu_hotplugmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hSpanish}hhsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget(/translations/sp_SP/core-api/cpu_hotplugmodnameN classnameN refexplicituh1hhh ubeh}(h]h ]h"]h$]h&]current_languageChinese (Simplified)uh1h hh _documenthsourceNlineNubhnote)}(hX{此文件的目的是为让中文读者更容易阅读和理解,而不是作为一个分支。 因此, 如果您对此文件有任何意见或更新,请先尝试更新原始英文文件。 如果您发现本文档与原始文件有任何不同或者有翻译问题,请发建议或者补丁给 该文件的译者,或者请求中文文档维护者和审阅者的帮助。h]h paragraph)}(hX{此文件的目的是为让中文读者更容易阅读和理解,而不是作为一个分支。 因此, 如果您对此文件有任何意见或更新,请先尝试更新原始英文文件。 如果您发现本文档与原始文件有任何不同或者有翻译问题,请发建议或者补丁给 该文件的译者,或者请求中文文档维护者和审阅者的帮助。h]hX{此文件的目的是为让中文读者更容易阅读和理解,而不是作为一个分支。 因此, 如果您对此文件有任何意见或更新,请先尝试更新原始英文文件。 如果您发现本文档与原始文件有任何不同或者有翻译问题,请发建议或者补丁给 该文件的译者,或者请求中文文档维护者和审阅者的帮助。}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hh5Documentation/translations/zh_CN/disclaimer-zh_CN.rsthKhhubah}(h]h ]h"]h$]h&]uh1hhhhhhhhNubh field_list)}(hhh](hfield)}(hhh](h field_name)}(hOriginalh]hOriginal}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhU/var/lib/git/docbuild/linux/Documentation/translations/zh_CN/core-api/cpu_hotplug.rsthKubh field_body)}(h&Documentation/core-api/cpu_hotplug.rsth]h)}(hhh]h&Documentation/core-api/cpu_hotplug.rst}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhhubah}(h]h ]h"]h$]h&]uh1hhhubeh}(h]h ]h"]h$]h&]uh1hhhhKhhhhubh)}(hhh](h)}(h翻译h]h翻译}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhhhKubh)}(h\司延腾 Yanteng Si 周彬彬 Binbin Zhou h]h)}(h[司延腾 Yanteng Si 周彬彬 Binbin Zhou h](h司延腾 Yanteng Si <}(hj hhhNhNubh reference)}(hsiyanteng@loongson.cnh]hsiyanteng@loongson.cn}(hjhhhNhNubah}(h]h ]h"]h$]h&]refurimailto:siyanteng@loongson.cnuh1jhj ubh> 周彬彬 Binbin Zhou <}(hj hhhNhNubj)}(hzhoubinbin@loongson.cnh]hzhoubinbin@loongson.cn}(hj+hhhNhNubah}(h]h ]h"]h$]h&]refurimailto:zhoubinbin@loongson.cnuh1jhj ubh>}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj ubah}(h]h ]h"]h$]h&]uh1hhhubeh}(h]h ]h"]h$]h&]uh1hhhhKhhhhubh)}(hhh](h)}(h校译h]h校译}(hjThhhNhNubah}(h]h ]h"]h$]h&]uh1hhjQhhhKubh)}(h*吴想成 Wu XiangCheng h]h)}(h)吴想成 Wu XiangCheng h](h吴想成 Wu XiangCheng <}(hjfhhhNhNubj)}(hbobwxc@email.cnh]hbobwxc@email.cn}(hjnhhhNhNubah}(h]h ]h"]h$]h&]refurimailto:bobwxc@email.cnuh1jhjfubh>}(hjfhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK hjbubah}(h]h ]h"]h$]h&]uh1hhjQubeh}(h]h ]h"]h$]h&]uh1hhhhK hhhhubeh}(h]h ]h"]h$]h&]uh1hhhhhhhhKubhtarget)}(h.. _cn_core_api_cpu_hotplug:h]h}(h]h ]h"]h$]h&]refidcn-core-api-cpu-hotpluguh1jhKhhhhhhubhsection)}(hhh](htitle)}(h内核中的CPU热拔插h]h内核中的CPU热拔插}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhKubh)}(hhh](h)}(hhh](h)}(h时间h]h时间}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhKubh)}(h 2021年9月h]h)}(hjh]h 2021年9月}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhjubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh)}(hhh](h)}(h作者h]h作者}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhKubh)}(hSebastian Andrzej Siewior , Rusty Russell , Srivatsa Vaddagiri , Ashok Raj , Joel Schopp , Thomas Gleixner h]h)}(hSebastian Andrzej Siewior , Rusty Russell , Srivatsa Vaddagiri , Ashok Raj , Joel Schopp , Thomas Gleixner h](hSebastian Andrzej Siewior <}(hjhhhNhNubj)}(hbigeasy@linutronix.deh]hbigeasy@linutronix.de}(hj hhhNhNubah}(h]h ]h"]h$]h&]refurimailto:bigeasy@linutronix.deuh1jhjubh>, Rusty Russell <}(hjhhhNhNubj)}(hrusty@rustcorp.com.auh]hrusty@rustcorp.com.au}(hjhhhNhNubah}(h]h ]h"]h$]h&]refurimailto:rusty@rustcorp.com.auuh1jhjubh>, Srivatsa Vaddagiri <}(hjhhhNhNubj)}(hvatsa@in.ibm.comh]hvatsa@in.ibm.com}(hj3hhhNhNubah}(h]h ]h"]h$]h&]refurimailto:vatsa@in.ibm.comuh1jhjubh>, Ashok Raj <}(hjhhhNhNubj)}(hashok.raj@intel.comh]hashok.raj@intel.com}(hjGhhhNhNubah}(h]h ]h"]h$]h&]refurimailto:ashok.raj@intel.comuh1jhjubh>, Joel Schopp <}(hjhhhNhNubj)}(hjschopp@austin.ibm.comh]hjschopp@austin.ibm.com}(hj[hhhNhNubah}(h]h ]h"]h$]h&]refurimailto:jschopp@austin.ibm.comuh1jhjubh>, Thomas Gleixner <}(hjhhhNhNubj)}(htglx@linutronix.deh]htglx@linutronix.de}(hjohhhNhNubah}(h]h ]h"]h$]h&]refurimailto:tglx@linutronix.deuh1jhjubh>}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhjubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubeh}(h]h ]h"]h$]h&]uh1hhjhhhhhKubj)}(hhh](j)}(h简介h]h简介}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhKubh)}(hX现代系统架构的演进已经在处理器中引入了先进的错误报告和纠正能力。有一些OEM也支 持可热拔插的NUMA(Non Uniform Memory Access,非统一内存访问)硬件,其中物理 节点的插入和移除需要支持CPU热插拔。h]hX现代系统架构的演进已经在处理器中引入了先进的错误报告和纠正能力。有一些OEM也支 持可热拔插的NUMA(Non Uniform Memory Access,非统一内存访问)硬件,其中物理 节点的插入和移除需要支持CPU热插拔。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh)}(h这样的进步要求内核可用的CPU被移除,要么是出于配置的原因,要么是出于RAS的目的, 以保持一个不需要的CPU不在系统执行路径。因此需要在Linux内核中支持CPU热拔插。h]h这样的进步要求内核可用的CPU被移除,要么是出于配置的原因,要么是出于RAS的目的, 以保持一个不需要的CPU不在系统执行路径。因此需要在Linux内核中支持CPU热拔插。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK"hjhhubh)}(hCPU热拔插支持的一个更新颖的用途是它在SMP的暂停恢复支持中的应用。双核和超线程支 持使得即使是笔记本电脑也能运行不支持这些方法的SMP内核。h]hCPU热拔插支持的一个更新颖的用途是它在SMP的暂停恢复支持中的应用。双核和超线程支 持使得即使是笔记本电脑也能运行不支持这些方法的SMP内核。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK%hjhhubeh}(h]id1ah ]h"]简介ah$]h&]uh1jhjhhhhhKubj)}(hhh](j)}(h命令行开关h]h命令行开关}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhK*ubhdefinition_list)}(hhh](hdefinition_list_item)}(h``maxcpus=n`` 限制启动时的CPU为 *n* 个。例如,如果你有四个CPU,使用 ``maxcpus=2`` 将只能启 动两个。你可以选择稍后让其他CPU上线。 h](hterm)}(h ``maxcpus=n``h]hliteral)}(hjh]h maxcpus=n}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jhhhK.hjubh definition)}(hhh]h)}(h限制启动时的CPU为 *n* 个。例如,如果你有四个CPU,使用 ``maxcpus=2`` 将只能启 动两个。你可以选择稍后让其他CPU上线。h](h限制启动时的CPU为 }(hjhhhNhNubhemphasis)}(h*n*h]hn}(hj$hhhNhNubah}(h]h ]h"]h$]h&]uh1j"hjubh/ 个。例如,如果你有四个CPU,使用 }(hjhhhNhNubj)}(h ``maxcpus=2``h]h maxcpus=2}(hj6hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubhD 将只能启 动两个。你可以选择稍后让其他CPU上线。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK-hjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhK.hjubj)}(h``nr_cpus=n`` 限制内核将支持的CPU总量。如果这里提供的数量低于实际可用的CPU数量,那么其他CPU 以后就不能上线了。 h](j)}(h ``nr_cpus=n``h]j)}(hj`h]h nr_cpus=n}(hjbhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj^ubah}(h]h ]h"]h$]h&]uh1jhhhK2hjZubj)}(hhh]h)}(h限制内核将支持的CPU总量。如果这里提供的数量低于实际可用的CPU数量,那么其他CPU 以后就不能上线了。h]h限制内核将支持的CPU总量。如果这里提供的数量低于实际可用的CPU数量,那么其他CPU 以后就不能上线了。}(hjxhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK1hjuubah}(h]h ]h"]h$]h&]uh1jhjZubeh}(h]h ]h"]h$]h&]uh1jhhhK2hjhhubj)}(h``possible_cpus=n`` 这个选项设置 ``cpu_possible_mask`` 中的 ``possible_cpus`` 位。 这个选项只限于X86和S390架构。 h](j)}(h``possible_cpus=n``h]j)}(hjh]hpossible_cpus=n}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jhhhK7hjubj)}(hhh](h)}(hH这个选项设置 ``cpu_possible_mask`` 中的 ``possible_cpus`` 位。h](h这个选项设置 }(hjhhhNhNubj)}(h``cpu_possible_mask``h]hcpu_possible_mask}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 中的 }(hjhhhNhNubj)}(h``possible_cpus``h]h possible_cpus}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 位。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK5hjubh)}(h(这个选项只限于X86和S390架构。h]h(这个选项只限于X86和S390架构。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK7hjubeh}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhK7hjhhubj)}(hH``cpu0_hotplug`` 允许关闭CPU0。 这个选项只限于X86架构。 h](j)}(h``cpu0_hotplug``h]j)}(hjh]h cpu0_hotplug}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jhhhKhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj6ubh 或 }(hj6hhhNhNubj)}(h``for_each_possible_cpu()``h]hfor_each_possible_cpu()}(hjPhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj6ubh 来进行迭代。宏 }(hj6hhhNhNubj)}(h``for_each_cpu()``h]hfor_each_cpu()}(hjbhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj6ubh1 可以用来迭代一个自定义的CPU掩码。}(hj6hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKRhjPhhubh)}(hH不要使用 ``cpumask_t`` 以外的任何东西来表示CPU的位图。h](h 不要使用 }(hjzhhhNhNubj)}(h ``cpumask_t``h]h cpumask_t}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjzubh. 以外的任何东西来表示CPU的位图。}(hjzhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKVhjPhhubeh}(h]id3ah ]h"] cpu位图ah$]h&]uh1jhjhhhhhK?ubj)}(hhh](j)}(h使用CPU热拔插h]h使用CPU热拔插}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhKZubh)}(h内核选项 *CONFIG_HOTPLUG_CPU* 需要被启用。它目前可用于多种架构,包括ARM、MIPS、 PowerPC和X86。配置是通过sysfs接口完成的::h](h 内核选项 }(hjhhhNhNubj#)}(h*CONFIG_HOTPLUG_CPU*h]hCONFIG_HOTPLUG_CPU}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j"hjubh| 需要被启用。它目前可用于多种架构,包括ARM、MIPS、 PowerPC和X86。配置是通过sysfs接口完成的:}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK\hjhhubh literal_block)}(hX$ ls -lh /sys/devices/system/cpu total 0 drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu0 drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu1 drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu2 drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu3 drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu4 drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu5 drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu6 drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu7 drwxr-xr-x 2 root root 0 Dec 21 16:33 hotplug -r--r--r-- 1 root root 4.0K Dec 21 16:33 offline -r--r--r-- 1 root root 4.0K Dec 21 16:33 online -r--r--r-- 1 root root 4.0K Dec 21 16:33 possible -r--r--r-- 1 root root 4.0K Dec 21 16:33 presenth]hX$ ls -lh /sys/devices/system/cpu total 0 drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu0 drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu1 drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu2 drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu3 drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu4 drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu5 drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu6 drwxr-xr-x 9 root root 0 Dec 21 16:33 cpu7 drwxr-xr-x 2 root root 0 Dec 21 16:33 hotplug -r--r--r-- 1 root root 4.0K Dec 21 16:33 offline -r--r--r-- 1 root root 4.0K Dec 21 16:33 online -r--r--r-- 1 root root 4.0K Dec 21 16:33 possible -r--r--r-- 1 root root 4.0K Dec 21 16:33 present}hjsbah}(h]h ]h"]h$]h&] xml:spacepreserveuh1jhhhK_hjhhubh)}(h文件 *offline* 、 *online* 、*possible* 、*present* 代表CPU掩码。每个CPU文件 夹包含一个 *online* 文件,控制逻辑上的开(1)和关(0)状态。要在逻辑上关闭CPU4::h](h文件 }(hjhhhNhNubj#)}(h *offline*h]hoffline}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j"hjubh 、 }(hjhhhNhNubj#)}(h*online*h]honline}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j"hjubh 、}(hjhhhNhNubj#)}(h *possible*h]hpossible}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j"hjubh 、}hjsbj#)}(h *present*h]hpresent}(hj#hhhNhNubah}(h]h ]h"]h$]h&]uh1j"hjubh3 代表CPU掩码。每个CPU文件 夹包含一个 }(hjhhhNhNubj#)}(h*online*h]honline}(hj5hhhNhNubah}(h]h ]h"]h$]h&]uh1j"hjubhV 文件,控制逻辑上的开(1)和关(0)状态。要在逻辑上关闭CPU4:}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKohjhhubj)}(hM$ echo 0 > /sys/devices/system/cpu/cpu4/online smpboot: CPU 4 is now offlineh]hM$ echo 0 > /sys/devices/system/cpu/cpu4/online smpboot: CPU 4 is now offline}hjMsbah}(h]h ]h"]h$]h&]jjuh1jhhhKrhjhhubh)}(h一旦CPU被关闭,它将从 */proc/interrupts* 、*/proc/cpuinfo* 中被删除,也不应该 被 *top* 命令显示出来。要让CPU4重新上线::h](h一旦CPU被关闭,它将从 }(hj[hhhNhNubj#)}(h*/proc/interrupts*h]h/proc/interrupts}(hjchhhNhNubah}(h]h ]h"]h$]h&]uh1j"hj[ubh 、}(hj[hhhNhNubj#)}(h*/proc/cpuinfo*h]h /proc/cpuinfo}(hjuhhhNhNubah}(h]h ]h"]h$]h&]uh1j"hj[ubh! 中被删除,也不应该 被 }(hj[hhhNhNubj#)}(h*top*h]htop}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j"hj[ubh- 命令显示出来。要让CPU4重新上线:}(hj[hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKuhjhhubj)}(h[$ echo 1 > /sys/devices/system/cpu/cpu4/online smpboot: Booting Node 0 Processor 4 APIC 0x1h]h[$ echo 1 > /sys/devices/system/cpu/cpu4/online smpboot: Booting Node 0 Processor 4 APIC 0x1}hjsbah}(h]h ]h"]h$]h&]jjuh1jhhhKxhjhhubh)}(hX6CPU又可以使用了。这应该对所有的CPU都有效。CPU0通常比较特殊,被排除在CPU热拔插之外。 在X86上,内核选项 *CONFIG_BOOTPARAM_HOTPLUG_CPU0* 必须被启用,以便能够关闭CPU0。 或者,可以使用内核命令选项 *cpu0_hotplug* 。CPU0的一些已知的依赖性:h](hCPU又可以使用了。这应该对所有的CPU都有效。CPU0通常比较特殊,被排除在CPU热拔插之外。 在X86上,内核选项 }(hjhhhNhNubj#)}(h*CONFIG_BOOTPARAM_HOTPLUG_CPU0*h]hCONFIG_BOOTPARAM_HOTPLUG_CPU0}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j"hjubhU 必须被启用,以便能够关闭CPU0。 或者,可以使用内核命令选项 }(hjhhhNhNubj#)}(h*cpu0_hotplug*h]h cpu0_hotplug}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j"hjubh$ 。CPU0的一些已知的依赖性:}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK{hjhhubh bullet_list)}(hhh](h list_item)}(hT从休眠/暂停中恢复。如果CPU0处于离线状态,休眠/暂停将失败。h]h)}(hjh]hT从休眠/暂停中恢复。如果CPU0处于离线状态,休眠/暂停将失败。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubj)}(hAPIC中断。如果检测到PIC中断,CPU0就不能被移除。 h]h)}(h@PIC中断。如果检测到PIC中断,CPU0就不能被移除。h]h@PIC中断。如果检测到PIC中断,CPU0就不能被移除。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubeh}(h]h ]h"]h$]h&]bullet*uh1jhhhKhjhhubh)}(hX如果你发现CPU0上有任何依赖性,请告知Fenghua Yu 。h](h@如果你发现CPU0上有任何依赖性,请告知Fenghua Yu <}(hjhhhNhNubj)}(hfenghua.yu@intel.comh]hfenghua.yu@intel.com}(hj%hhhNhNubah}(h]h ]h"]h$]h&]refurimailto:fenghua.yu@intel.comuh1jhjubh>。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubeh}(h]id4ah ]h"]使用cpu热拔插ah$]h&]uh1jhjhhhhhKZubj)}(hhh](j)}(hCPU的热拔插协作h]hCPU的热拔插协作}(hjJhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjGhhhhhKubj)}(hhh](j)}(h 下线情况h]h 下线情况}(hj[hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjXhhhhhKubh)}(h一旦CPU被逻辑关闭,注册的热插拔状态的清除回调将被调用,从 ``CPUHP_ONLINE`` 开始,到 ``CPUHP_OFFLINE`` 状态结束。这包括:h](hU一旦CPU被逻辑关闭,注册的热插拔状态的清除回调将被调用,从 }(hjihhhNhNubj)}(h``CPUHP_ONLINE``h]h CPUHP_ONLINE}(hjqhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjiubh 开始,到 }(hjihhhNhNubj)}(h``CPUHP_OFFLINE``h]h CPUHP_OFFLINE}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjiubh 状态结束。这包括:}(hjihhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjXhhubj)}(hhh](j)}(h]如果任务因暂停操作而被冻结,那么 *cpuhp_tasks_frozen* 将被设置为true。 h]h)}(h\如果任务因暂停操作而被冻结,那么 *cpuhp_tasks_frozen* 将被设置为true。h](h1如果任务因暂停操作而被冻结,那么 }(hjhhhNhNubj#)}(h*cpuhp_tasks_frozen*h]hcpuhp_tasks_frozen}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1j"hjubh 将被设置为true。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubj)}(h所有进程都会从这个将要离线的CPU迁移到新的CPU上。新的CPU是从每个进程的当前cpuset中 选择的,它可能是所有在线CPU的一个子集。 h]h)}(h所有进程都会从这个将要离线的CPU迁移到新的CPU上。新的CPU是从每个进程的当前cpuset中 选择的,它可能是所有在线CPU的一个子集。h]h所有进程都会从这个将要离线的CPU迁移到新的CPU上。新的CPU是从每个进程的当前cpuset中 选择的,它可能是所有在线CPU的一个子集。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubj)}(h=所有针对这个CPU的中断都被迁移到新的CPU上。 h]h)}(h<所有针对这个CPU的中断都被迁移到新的CPU上。h]h<所有针对这个CPU的中断都被迁移到新的CPU上。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubj)}(h+计时器也会被迁移到新的CPU上。 h]h)}(h*计时器也会被迁移到新的CPU上。h]h*计时器也会被迁移到新的CPU上。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubj)}(hw一旦所有的服务被迁移,内核会调用一个特定的例程 ``__cpu_disable()`` 来进行特定的清 理。 h]h)}(hv一旦所有的服务被迁移,内核会调用一个特定的例程 ``__cpu_disable()`` 来进行特定的清 理。h](hF一旦所有的服务被迁移,内核会调用一个特定的例程 }(hjhhhNhNubj)}(h``__cpu_disable()``h]h__cpu_disable()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 来进行特定的清 理。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubeh}(h]h ]h"]h$]h&]jjuh1jhhhKhjXhhubeh}(h]id6ah ]h"] 下线情况ah$]h&]uh1jhjGhhhhhKubeh}(h]id5ah ]h"]cpu的热拔插协作ah$]h&]uh1jhjhhhhhKubj)}(hhh](j)}(hCPU热插拔APIh]hCPU热插拔API}(hjShhhNhNubah}(h]h ]h"]h$]h&]uh1jhjPhhhhhKubj)}(hhh](j)}(hCPU热拔插状态机h]hCPU热拔插状态机}(hjdhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjahhhhhKubh)}(hCPU热插拔使用一个从CPUHP_OFFLINE到CPUHP_ONLINE的线性状态空间的普通状态机。每个状态都 有一个startup和teardown的回调。h]hCPU热插拔使用一个从CPUHP_OFFLINE到CPUHP_ONLINE的线性状态空间的普通状态机。每个状态都 有一个startup和teardown的回调。}(hjrhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjahhubh)}(h当一个CPU上线时,将按顺序调用startup回调,直到达到CPUHP_ONLINE状态。当设置状态的回调 或将实例添加到多实例状态时,也可以调用它们。h]h当一个CPU上线时,将按顺序调用startup回调,直到达到CPUHP_ONLINE状态。当设置状态的回调 或将实例添加到多实例状态时,也可以调用它们。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjahhubh)}(h当一个CPU下线时,将按相反的顺序依次调用teardown回调,直到达到CPUHP_OFFLINE状态。当删 除状态的回调或从多实例状态中删除实例时,也可以调用它们。h]h当一个CPU下线时,将按相反的顺序依次调用teardown回调,直到达到CPUHP_OFFLINE状态。当删 除状态的回调或从多实例状态中删除实例时,也可以调用它们。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjahhubh)}(h如果某个使用场景只需要一个方向的热插拔操作回调(CPU上线或CPU下线),则在设置状态时, 可以将另一个不需要的回调设置为NULL。h]h如果某个使用场景只需要一个方向的热插拔操作回调(CPU上线或CPU下线),则在设置状态时, 可以将另一个不需要的回调设置为NULL。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjahhubh)}(h%状态空间被划分成三个阶段:h]h%状态空间被划分成三个阶段:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjahhubj)}(hhh](j)}(hXPREPARE阶段 PREPARE阶段涵盖了从CPUHP_OFFLINE到CPUHP_BRINGUP_CPU之间的状态空间。 在该阶段中,startup回调在CPU上线操作启动CPU之前被调用,teardown回调在CPU下线操作使 CPU功能失效之后被调用。 这些回调是在控制CPU上调用的,因为它们显然不能在热插拔的CPU上运行,此时热插拔的CPU要 么还没有启动,要么已经功能失效。 startup回调用于设置CPU成功上线所需要的资源。teardown回调用于释放资源或在热插拔的CPU 功能失效后,将待处理的工作转移到在线的CPU上。 允许startup回调失败。如果回调失败,CPU上线操作被中止,CPU将再次被降到之前的状态(通 常是CPUHP_OFFLINE)。 本阶段中的teardown回调不允许失败。 h](h)}(h PREPARE阶段h]h PREPARE阶段}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubh)}(hRPREPARE阶段涵盖了从CPUHP_OFFLINE到CPUHP_BRINGUP_CPU之间的状态空间。h]hRPREPARE阶段涵盖了从CPUHP_OFFLINE到CPUHP_BRINGUP_CPU之间的状态空间。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubh)}(h在该阶段中,startup回调在CPU上线操作启动CPU之前被调用,teardown回调在CPU下线操作使 CPU功能失效之后被调用。h]h在该阶段中,startup回调在CPU上线操作启动CPU之前被调用,teardown回调在CPU下线操作使 CPU功能失效之后被调用。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubh)}(h这些回调是在控制CPU上调用的,因为它们显然不能在热插拔的CPU上运行,此时热插拔的CPU要 么还没有启动,要么已经功能失效。h]h这些回调是在控制CPU上调用的,因为它们显然不能在热插拔的CPU上运行,此时热插拔的CPU要 么还没有启动,要么已经功能失效。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubh)}(hstartup回调用于设置CPU成功上线所需要的资源。teardown回调用于释放资源或在热插拔的CPU 功能失效后,将待处理的工作转移到在线的CPU上。h]hstartup回调用于设置CPU成功上线所需要的资源。teardown回调用于释放资源或在热插拔的CPU 功能失效后,将待处理的工作转移到在线的CPU上。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubh)}(h允许startup回调失败。如果回调失败,CPU上线操作被中止,CPU将再次被降到之前的状态(通 常是CPUHP_OFFLINE)。h]h允许startup回调失败。如果回调失败,CPU上线操作被中止,CPU将再次被降到之前的状态(通 常是CPUHP_OFFLINE)。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubh)}(h/本阶段中的teardown回调不允许失败。h]h/本阶段中的teardown回调不允许失败。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubeh}(h]h ]h"]h$]h&]uh1jhjhhhhhNubj)}(hXSTARTING阶段 STARTING阶段涵盖了CPUHP_BRINGUP_CPU + 1到CPUHP_AP_ONLINE之间的状态空间。 该阶段中的startup回调是在早期CPU设置代码中的CPU上线操作期间,禁用中断的情况下在热拔 插的CPU上被调用。teardown回调是在CPU完全关闭前不久的CPU下线操作期间,禁用中断的情况 下在热拔插的CPU上被调用。 该阶段中的回调不允许失败。 回调用于低级别的硬件初始化/关机和核心子系统。 h](h)}(hSTARTING阶段h]hSTARTING阶段}(hj+ hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj' ubh)}(hVSTARTING阶段涵盖了CPUHP_BRINGUP_CPU + 1到CPUHP_AP_ONLINE之间的状态空间。h]hVSTARTING阶段涵盖了CPUHP_BRINGUP_CPU + 1到CPUHP_AP_ONLINE之间的状态空间。}(hj9 hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj' ubh)}(hX该阶段中的startup回调是在早期CPU设置代码中的CPU上线操作期间,禁用中断的情况下在热拔 插的CPU上被调用。teardown回调是在CPU完全关闭前不久的CPU下线操作期间,禁用中断的情况 下在热拔插的CPU上被调用。h]hX该阶段中的startup回调是在早期CPU设置代码中的CPU上线操作期间,禁用中断的情况下在热拔 插的CPU上被调用。teardown回调是在CPU完全关闭前不久的CPU下线操作期间,禁用中断的情况 下在热拔插的CPU上被调用。}(hjG hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj' ubh)}(h'该阶段中的回调不允许失败。h]h'该阶段中的回调不允许失败。}(hjU hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj' ubh)}(hC回调用于低级别的硬件初始化/关机和核心子系统。h]hC回调用于低级别的硬件初始化/关机和核心子系统。}(hjc hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj' ubeh}(h]h ]h"]h$]h&]uh1jhjhhhhhNubj)}(hXONLINE阶段 ONLINE阶段涵盖了CPUHP_AP_ONLINE + 1到CPUHP_ONLINE之间的状态空间。 该阶段中的startup回调是在CPU上线时在热插拔的CPU上调用的。teardown回调是在CPU下线操 作时在热插拔CPU上调用的。 回调是在每个CPU热插拔线程的上下文中调用的,该线程绑定在热插拔的CPU上。回调是在启用 中断和抢占的情况下调用的。 允许回调失败。如果回调失败,CPU热插拔操作被中止,CPU将恢复到之前的状态。 h](h)}(h ONLINE阶段h]h ONLINE阶段}(hj{ hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjw ubh)}(hOONLINE阶段涵盖了CPUHP_AP_ONLINE + 1到CPUHP_ONLINE之间的状态空间。h]hOONLINE阶段涵盖了CPUHP_AP_ONLINE + 1到CPUHP_ONLINE之间的状态空间。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjw ubh)}(h该阶段中的startup回调是在CPU上线时在热插拔的CPU上调用的。teardown回调是在CPU下线操 作时在热插拔CPU上调用的。h]h该阶段中的startup回调是在CPU上线时在热插拔的CPU上调用的。teardown回调是在CPU下线操 作时在热插拔CPU上调用的。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjw ubh)}(h回调是在每个CPU热插拔线程的上下文中调用的,该线程绑定在热插拔的CPU上。回调是在启用 中断和抢占的情况下调用的。h]h回调是在每个CPU热插拔线程的上下文中调用的,该线程绑定在热插拔的CPU上。回调是在启用 中断和抢占的情况下调用的。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjw ubh)}(hi允许回调失败。如果回调失败,CPU热插拔操作被中止,CPU将恢复到之前的状态。h]hi允许回调失败。如果回调失败,CPU热插拔操作被中止,CPU将恢复到之前的状态。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjw ubeh}(h]h ]h"]h$]h&]uh1jhjhhhhhNubeh}(h]h ]h"]h$]h&]jjuh1jhhhKhjahhubeh}(h]id7ah ]h"]cpu热拔插状态机ah$]h&]uh1jhjPhhhhhKubj)}(hhh](j)}(hCPU 上线/下线操作h]hCPU 上线/下线操作}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj hhhhhKubh)}(h#一个成功的上线操作如下::h]h"一个成功的上线操作如下:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj hhubj)}(hX[CPUHP_OFFLINE] [CPUHP_OFFLINE + 1]->startup() -> 成功 [CPUHP_OFFLINE + 2]->startup() -> 成功 [CPUHP_OFFLINE + 3] -> 略过,因为startup == NULL ... [CPUHP_BRINGUP_CPU]->startup() -> 成功 === PREPARE阶段结束 [CPUHP_BRINGUP_CPU + 1]->startup() -> 成功 ... [CPUHP_AP_ONLINE]->startup() -> 成功 === STARTUP阶段结束 [CPUHP_AP_ONLINE + 1]->startup() -> 成功 ... [CPUHP_ONLINE - 1]->startup() -> 成功 [CPUHP_ONLINE]h]hX[CPUHP_OFFLINE] [CPUHP_OFFLINE + 1]->startup() -> 成功 [CPUHP_OFFLINE + 2]->startup() -> 成功 [CPUHP_OFFLINE + 3] -> 略过,因为startup == NULL ... [CPUHP_BRINGUP_CPU]->startup() -> 成功 === PREPARE阶段结束 [CPUHP_BRINGUP_CPU + 1]->startup() -> 成功 ... [CPUHP_AP_ONLINE]->startup() -> 成功 === STARTUP阶段结束 [CPUHP_AP_ONLINE + 1]->startup() -> 成功 ... [CPUHP_ONLINE - 1]->startup() -> 成功 [CPUHP_ONLINE]}hj sbah}(h]h ]h"]h$]h&]jjuh1jhhhKhj hhubh)}(h#一个成功的下线操作如下::h]h"一个成功的下线操作如下:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj hhubj)}(hX[CPUHP_ONLINE] [CPUHP_ONLINE - 1]->teardown() -> 成功 ... [CPUHP_AP_ONLINE + 1]->teardown() -> 成功 === STARTUP阶段开始 [CPUHP_AP_ONLINE]->teardown() -> 成功 ... [CPUHP_BRINGUP_ONLINE - 1]->teardown() ... === PREPARE阶段开始 [CPUHP_BRINGUP_CPU]->teardown() [CPUHP_OFFLINE + 3]->teardown() [CPUHP_OFFLINE + 2] -> 略过,因为teardown == NULL [CPUHP_OFFLINE + 1]->teardown() [CPUHP_OFFLINE]h]hX[CPUHP_ONLINE] [CPUHP_ONLINE - 1]->teardown() -> 成功 ... [CPUHP_AP_ONLINE + 1]->teardown() -> 成功 === STARTUP阶段开始 [CPUHP_AP_ONLINE]->teardown() -> 成功 ... [CPUHP_BRINGUP_ONLINE - 1]->teardown() ... === PREPARE阶段开始 [CPUHP_BRINGUP_CPU]->teardown() [CPUHP_OFFLINE + 3]->teardown() [CPUHP_OFFLINE + 2] -> 略过,因为teardown == NULL [CPUHP_OFFLINE + 1]->teardown() [CPUHP_OFFLINE]}hj sbah}(h]h ]h"]h$]h&]jjuh1jhhhKhj hhubh)}(h#一个失败的上线操作如下::h]h"一个失败的上线操作如下:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj hhubj)}(hX^[CPUHP_OFFLINE] [CPUHP_OFFLINE + 1]->startup() -> 成功 [CPUHP_OFFLINE + 2]->startup() -> 成功 [CPUHP_OFFLINE + 3] -> 略过,因为startup == NULL ... [CPUHP_BRINGUP_CPU]->startup() -> 成功 === PREPARE阶段结束 [CPUHP_BRINGUP_CPU + 1]->startup() -> 成功 ... [CPUHP_AP_ONLINE]->startup() -> 成功 === STARTUP阶段结束 [CPUHP_AP_ONLINE + 1]->startup() -> 成功 --- [CPUHP_AP_ONLINE + N]->startup() -> 失败 [CPUHP_AP_ONLINE + (N - 1)]->teardown() ... [CPUHP_AP_ONLINE + 1]->teardown() === STARTUP阶段开始 [CPUHP_AP_ONLINE]->teardown() ... [CPUHP_BRINGUP_ONLINE - 1]->teardown() ... === PREPARE阶段开始 [CPUHP_BRINGUP_CPU]->teardown() [CPUHP_OFFLINE + 3]->teardown() [CPUHP_OFFLINE + 2] -> 略过,因为teardown == NULL [CPUHP_OFFLINE + 1]->teardown() [CPUHP_OFFLINE]h]hX^[CPUHP_OFFLINE] [CPUHP_OFFLINE + 1]->startup() -> 成功 [CPUHP_OFFLINE + 2]->startup() -> 成功 [CPUHP_OFFLINE + 3] -> 略过,因为startup == NULL ... [CPUHP_BRINGUP_CPU]->startup() -> 成功 === PREPARE阶段结束 [CPUHP_BRINGUP_CPU + 1]->startup() -> 成功 ... [CPUHP_AP_ONLINE]->startup() -> 成功 === STARTUP阶段结束 [CPUHP_AP_ONLINE + 1]->startup() -> 成功 --- [CPUHP_AP_ONLINE + N]->startup() -> 失败 [CPUHP_AP_ONLINE + (N - 1)]->teardown() ... [CPUHP_AP_ONLINE + 1]->teardown() === STARTUP阶段开始 [CPUHP_AP_ONLINE]->teardown() ... [CPUHP_BRINGUP_ONLINE - 1]->teardown() ... === PREPARE阶段开始 [CPUHP_BRINGUP_CPU]->teardown() [CPUHP_OFFLINE + 3]->teardown() [CPUHP_OFFLINE + 2] -> 略过,因为teardown == NULL [CPUHP_OFFLINE + 1]->teardown() [CPUHP_OFFLINE]}hj, sbah}(h]h ]h"]h$]h&]jjuh1jhhhMhj hhubh)}(h#一个失败的下线操作如下::h]h"一个失败的下线操作如下:}(hj: hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj hhubj)}(h[CPUHP_ONLINE] [CPUHP_ONLINE - 1]->teardown() -> 成功 ... [CPUHP_ONLINE - N]->teardown() -> 失败 [CPUHP_ONLINE - (N - 1)]->startup() ... [CPUHP_ONLINE - 1]->startup() [CPUHP_ONLINE]h]h[CPUHP_ONLINE] [CPUHP_ONLINE - 1]->teardown() -> 成功 ... [CPUHP_ONLINE - N]->teardown() -> 失败 [CPUHP_ONLINE - (N - 1)]->startup() ... [CPUHP_ONLINE - 1]->startup() [CPUHP_ONLINE]}hjH sbah}(h]h ]h"]h$]h&]jjuh1jhhhMhj hhubh)}(hr递归失败不能被合理地处理。 请看下面的例子,由于下线操作失败而导致的递归失败::h]hq递归失败不能被合理地处理。 请看下面的例子,由于下线操作失败而导致的递归失败:}(hjV hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM(hj hhubj)}(h[CPUHP_ONLINE] [CPUHP_ONLINE - 1]->teardown() -> 成功 ... [CPUHP_ONLINE - N]->teardown() -> 失败 [CPUHP_ONLINE - (N - 1)]->startup() -> 成功 [CPUHP_ONLINE - (N - 2)]->startup() -> 失败h]h[CPUHP_ONLINE] [CPUHP_ONLINE - 1]->teardown() -> 成功 ... [CPUHP_ONLINE - N]->teardown() -> 失败 [CPUHP_ONLINE - (N - 1)]->startup() -> 成功 [CPUHP_ONLINE - (N - 2)]->startup() -> 失败}hjd sbah}(h]h ]h"]h$]h&]jjuh1jhhhM+hj hhubh)}(h_CPU热插拔状态机在此停止,且不再尝试回滚,因为这可能会导致死循环::h]h^CPU热插拔状态机在此停止,且不再尝试回滚,因为这可能会导致死循环:}(hjr hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM2hj hhubj)}(hX[CPUHP_ONLINE - (N - 1)]->teardown() -> 成功 [CPUHP_ONLINE - N]->teardown() -> 失败 [CPUHP_ONLINE - (N - 1)]->startup() -> 成功 [CPUHP_ONLINE - (N - 2)]->startup() -> 失败 [CPUHP_ONLINE - (N - 1)]->teardown() -> 成功 [CPUHP_ONLINE - N]->teardown() -> 失败h]hX[CPUHP_ONLINE - (N - 1)]->teardown() -> 成功 [CPUHP_ONLINE - N]->teardown() -> 失败 [CPUHP_ONLINE - (N - 1)]->startup() -> 成功 [CPUHP_ONLINE - (N - 2)]->startup() -> 失败 [CPUHP_ONLINE - (N - 1)]->teardown() -> 成功 [CPUHP_ONLINE - N]->teardown() -> 失败}hj sbah}(h]h ]h"]h$]h&]jjuh1jhhhM4hj hhubh)}(hJ周而复始,不断重复。在这种情况下,CPU留在该状态中::h]hI周而复始,不断重复。在这种情况下,CPU留在该状态中:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM;hj hhubj)}(h[CPUHP_ONLINE - (N - 1)]h]h[CPUHP_ONLINE - (N - 1)]}hj sbah}(h]h ]h"]h$]h&]jjuh1jhhhM=hj hhubh)}(hc这至少可以让系统取得进展,让用户有机会进行调试,甚至解决这个问题。h]hc这至少可以让系统取得进展,让用户有机会进行调试,甚至解决这个问题。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM?hj hhubeh}(h]id8ah ]h"]cpu 上线/下线操作ah$]h&]uh1jhjPhhhhhKubj)}(hhh](j)}(h分配一个状态h]h分配一个状态}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj hhhhhMBubh)}(h.有两种方式分配一个CPU热插拔状态:h]h.有两种方式分配一个CPU热插拔状态:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMDhj hhubj)}(hhh](j)}(hX静态分配 当子系统或驱动程序有相对于其他CPU热插拔状态的排序要求时,必须使用静态分配。例如, 在CPU上线操作期间,PERF核心startup回调必须在PERF驱动startup回调之前被调用。在CPU 下线操作中,驱动teardown回调必须在核心teardown回调之前调用。静态分配的状态由 cpuhp_state枚举中的常量描述,可以在include/linux/cpuhotplug.h中找到。 在适当的位置将状态插入枚举中,这样就满足了排序要求。状态常量必须被用于状态的设置 和移除。 当状态回调不是在运行时设置的,并且是kernel/cpu.c中CPU热插拔状态数组初始化的一部分 时,也需要静态分配。 h](h)}(h 静态分配h]h 静态分配}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMFhj ubh)}(hX当子系统或驱动程序有相对于其他CPU热插拔状态的排序要求时,必须使用静态分配。例如, 在CPU上线操作期间,PERF核心startup回调必须在PERF驱动startup回调之前被调用。在CPU 下线操作中,驱动teardown回调必须在核心teardown回调之前调用。静态分配的状态由 cpuhp_state枚举中的常量描述,可以在include/linux/cpuhotplug.h中找到。h]hX当子系统或驱动程序有相对于其他CPU热插拔状态的排序要求时,必须使用静态分配。例如, 在CPU上线操作期间,PERF核心startup回调必须在PERF驱动startup回调之前被调用。在CPU 下线操作中,驱动teardown回调必须在核心teardown回调之前调用。静态分配的状态由 cpuhp_state枚举中的常量描述,可以在include/linux/cpuhotplug.h中找到。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMHhj ubh)}(h在适当的位置将状态插入枚举中,这样就满足了排序要求。状态常量必须被用于状态的设置 和移除。h]h在适当的位置将状态插入枚举中,这样就满足了排序要求。状态常量必须被用于状态的设置 和移除。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMMhj ubh)}(h当状态回调不是在运行时设置的,并且是kernel/cpu.c中CPU热插拔状态数组初始化的一部分 时,也需要静态分配。h]h当状态回调不是在运行时设置的,并且是kernel/cpu.c中CPU热插拔状态数组初始化的一部分 时,也需要静态分配。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMPhj ubeh}(h]h ]h"]h$]h&]uh1jhj hhhhhNubj)}(hX;动态分配 当对状态回调没有排序要求时,动态分配是首选方法。状态编号由setup函数分配,并在成功 后返回给调用者。 只有PREPARE和ONLINE阶段提供了一个动态分配范围。STARTING阶段则没有,因为该部分的大多 数回调都有明确的排序要求。 h](h)}(h 动态分配h]h 动态分配}(hj( hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMShj$ ubh)}(h当对状态回调没有排序要求时,动态分配是首选方法。状态编号由setup函数分配,并在成功 后返回给调用者。h]h当对状态回调没有排序要求时,动态分配是首选方法。状态编号由setup函数分配,并在成功 后返回给调用者。}(hj6 hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMUhj$ ubh)}(h只有PREPARE和ONLINE阶段提供了一个动态分配范围。STARTING阶段则没有,因为该部分的大多 数回调都有明确的排序要求。h]h只有PREPARE和ONLINE阶段提供了一个动态分配范围。STARTING阶段则没有,因为该部分的大多 数回调都有明确的排序要求。}(hjD hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMXhj$ ubeh}(h]h ]h"]h$]h&]uh1jhj hhhhhNubeh}(h]h ]h"]h$]h&]jjuh1jhhhMFhj hhubeh}(h]id9ah ]h"]分配一个状态ah$]h&]uh1jhjPhhhhhMBubj)}(hhh](j)}(hCPU热插拔状态的设置h]hCPU热插拔状态的设置}(hji hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjf hhhhhM\ubh)}(h6核心代码提供了以下函数用来设置状态:h]h6核心代码提供了以下函数用来设置状态:}(hjw hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM^hjf hhubj)}(hhh](j)}(h1cpuhp_setup_state(state, name, startup, teardown)h]h)}(hj h]h1cpuhp_setup_state(state, name, startup, teardown)}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM`hj ubah}(h]h ]h"]h$]h&]uh1jhj hhhhhNubj)}(h9cpuhp_setup_state_nocalls(state, name, startup, teardown)h]h)}(hj h]h9cpuhp_setup_state_nocalls(state, name, startup, teardown)}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMahj ubah}(h]h ]h"]h$]h&]uh1jhj hhhhhNubj)}(h ubah}(h]h ]h"]h$]h&]uh1j` hj; ubja )}(hhh]h)}(h对应ONLINE阶段中的状态h]h对应ONLINE阶段中的状态}(hjX hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM{hjU ubah}(h]h ]h"]h$]h&]uh1j` hj; ubeh}(h]h ]h"]h$]h&]uh1j[ hjX ubj\ )}(hhh](ja )}(hhh]h)}(hofflineh]hoffline}(hjx hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM}hju ubah}(h]h ]h"]h$]h&]uh1j` hjr ubja )}(hhh]h)}(h4对应ONLINE阶段中不提供startup回调的状态h]h4对应ONLINE阶段中不提供startup回调的状态}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM}hj ubah}(h]h ]h"]h$]h&]uh1j` hjr ubeh}(h]h ]h"]h$]h&]uh1j[ hjX ubeh}(h]h ]h"]h$]h&]uh1jV hj= ubeh}(h]h ]h"]h$]h&]colsKuh1j; hj8 ubah}(h]h ]h"]h$]h&]uh1j6 hjf hhhhhNubh)}(h由于@name参数只用于sysfs和检测,如果其他mode描述符比常见的描述符更好地描述状态的性质, 也可以使用。h]h由于@name参数只用于sysfs和检测,如果其他mode描述符比常见的描述符更好地描述状态的性质, 也可以使用。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjf hhubh)}(h]@name参数的示例:"perf/online", "perf/x86:prepare", "RCU/tree:dying", "sched/waitempty"h]hm@name参数的示例:”perf/online”, “perf/x86:prepare”, “RCU/tree:dying”, “sched/waitempty”}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjf hhubh)}(h@startup参数是一个指向回调的函数指针,在CPU上线操作时被调用。若应用不需要startup 回调,则将该指针设为NULL。h]h@startup参数是一个指向回调的函数指针,在CPU上线操作时被调用。若应用不需要startup 回调,则将该指针设为NULL。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjf hhubh)}(h@teardown参数是一个指向回调的函数指针,在CPU下线操作时调用。若应用不需要teardown 回调,则将该指针设为NULL。h]h@teardown参数是一个指向回调的函数指针,在CPU下线操作时调用。若应用不需要teardown 回调,则将该指针设为NULL。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjf hhubh)}(h=这些函数在处理已注册回调的方式上有所不同:h]h=这些函数在处理已注册回调的方式上有所不同:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjf hhubh block_quote)}(hX* cpuhp_setup_state_nocalls(), cpuhp_setup_state_nocalls_cpuslocked()和 cpuhp_setup_state_multi()只注册回调。 * cpuhp_setup_state()和cpuhp_setup_state_cpuslocked()注册回调,并对当前状态大于新 安装状态的所有在线CPU调用@startup回调(如果不是NULL)。根据状态阶段,回调要么在 当前的CPU上调用(PREPARE阶段),要么在CPU的热插拔线程中调用每个在线CPU(ONLINE阶段)。 如果CPU N的回调失败,那么CPU 0...N-1的teardown回调被调用以回滚操作。状态设置失败, 状态的回调没有被注册,在动态分配的情况下,分配的状态被释放。 h]j)}(hhh](j)}(hscpuhp_setup_state_nocalls(), cpuhp_setup_state_nocalls_cpuslocked()和 cpuhp_setup_state_multi()只注册回调。 h]h)}(hrcpuhp_setup_state_nocalls(), cpuhp_setup_state_nocalls_cpuslocked()和 cpuhp_setup_state_multi()只注册回调。h]hrcpuhp_setup_state_nocalls(), cpuhp_setup_state_nocalls_cpuslocked()和 cpuhp_setup_state_multi()只注册回调。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj ubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hXcpuhp_setup_state()和cpuhp_setup_state_cpuslocked()注册回调,并对当前状态大于新 安装状态的所有在线CPU调用@startup回调(如果不是NULL)。根据状态阶段,回调要么在 当前的CPU上调用(PREPARE阶段),要么在CPU的热插拔线程中调用每个在线CPU(ONLINE阶段)。 如果CPU N的回调失败,那么CPU 0...N-1的teardown回调被调用以回滚操作。状态设置失败, 状态的回调没有被注册,在动态分配的情况下,分配的状态被释放。 h](h)}(hXEcpuhp_setup_state()和cpuhp_setup_state_cpuslocked()注册回调,并对当前状态大于新 安装状态的所有在线CPU调用@startup回调(如果不是NULL)。根据状态阶段,回调要么在 当前的CPU上调用(PREPARE阶段),要么在CPU的热插拔线程中调用每个在线CPU(ONLINE阶段)。h]hXEcpuhp_setup_state()和cpuhp_setup_state_cpuslocked()注册回调,并对当前状态大于新 安装状态的所有在线CPU调用@startup回调(如果不是NULL)。根据状态阶段,回调要么在 当前的CPU上调用(PREPARE阶段),要么在CPU的热插拔线程中调用每个在线CPU(ONLINE阶段)。}(hj'hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj#ubh)}(h如果CPU N的回调失败,那么CPU 0...N-1的teardown回调被调用以回滚操作。状态设置失败, 状态的回调没有被注册,在动态分配的情况下,分配的状态被释放。h]h如果CPU N的回调失败,那么CPU 0...N-1的teardown回调被调用以回滚操作。状态设置失败, 状态的回调没有被注册,在动态分配的情况下,分配的状态被释放。W}(hj5hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj#ubeh}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]jjuh1jhhhMhjubah}(h]h ]h"]h$]h&]uh1jhhhMhjf hhubh)}(h状态设置和回调调用是针对CPU热拔插操作进行序列化的。如果设置函数必须从CPU热插拔的读 锁定区域调用,那么必须使用_cpuslocked()变体。这些函数不能在CPU热拔插回调中使用。h]h状态设置和回调调用是针对CPU热拔插操作进行序列化的。如果设置函数必须从CPU热插拔的读 锁定区域调用,那么必须使用_cpuslocked()变体。这些函数不能在CPU热拔插回调中使用。}(hjUhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjf hhubj)}(hhh]j)}(hXe函数返回值: ======== ========================================================== 0 静态分配的状态设置成功 >0 动态分配的状态设置成功 返回的数值是被分配的状态编号。如果状态回调后来必须被移除, 例如模块移除,那么这个数值必须由调用者保存,并作为状态移 除函数的@state参数。对于多实例状态,动态分配的状态编号也 需要作为实例添加/删除操作的@state参数。 <0 操作失败 ======== ========================================================== h](j)}(h函数返回值:h]h函数返回值:}(hjjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhhhMhjfubj)}(hhh]j7 )}(hhh]j< )}(hhh](jA )}(hhh]h}(h]h ]h"]h$]h&]colwidthKuh1j@ hj~ubjA )}(hhh]h}(h]h ]h"]h$]h&]colwidthK:uh1j@ hj~ubjW )}(hhh](j\ )}(hhh](ja )}(hhh]h)}(h0h]h0}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j` hjubja )}(hhh]h)}(h!静态分配的状态设置成功h]h!静态分配的状态设置成功}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j` hjubeh}(h]h ]h"]h$]h&]uh1j[ hjubj\ )}(hhh](ja )}(hhh]h)}(h>0h]h>0}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j` hjubja )}(hhh](h)}(h!动态分配的状态设置成功h]h!动态分配的状态设置成功}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubh)}(hX6返回的数值是被分配的状态编号。如果状态回调后来必须被移除, 例如模块移除,那么这个数值必须由调用者保存,并作为状态移 除函数的@state参数。对于多实例状态,动态分配的状态编号也 需要作为实例添加/删除操作的@state参数。h]hX6返回的数值是被分配的状态编号。如果状态回调后来必须被移除, 例如模块移除,那么这个数值必须由调用者保存,并作为状态移 除函数的@state参数。对于多实例状态,动态分配的状态编号也 需要作为实例添加/删除操作的@state参数。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubeh}(h]h ]h"]h$]h&]uh1j` hjubeh}(h]h ]h"]h$]h&]uh1j[ hjubj\ )}(hhh](ja )}(hhh]h)}(h<0h]h<0}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1j` hjubja )}(hhh]h)}(h 操作失败h]h 操作失败}(hj1hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj.ubah}(h]h ]h"]h$]h&]uh1j` hjubeh}(h]h ]h"]h$]h&]uh1j[ hjubeh}(h]h ]h"]h$]h&]uh1jV hj~ubeh}(h]h ]h"]h$]h&]colsKuh1j; hj{ubah}(h]h ]h"]h$]h&]uh1j6 hjxubah}(h]h ]h"]h$]h&]uh1jhjfubeh}(h]h ]h"]h$]h&]uh1jhhhMhjcubah}(h]h ]h"]h$]h&]uh1jhjf hhhhhNubeh}(h]id10ah ]h"]cpu热插拔状态的设置ah$]h&]uh1jhjPhhhhhM\ubj)}(hhh](j)}(h移除CPU热拔插状态h]h移除CPU热拔插状态}(hj{hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjxhhhhhMubh)}(hE为了移除一个之前设置好的状态,提供了如下函数:h]hE为了移除一个之前设置好的状态,提供了如下函数:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjxhhubj)}(hhh](j)}(hcpuhp_remove_state(state)h]h)}(hjh]hcpuhp_remove_state(state)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubj)}(h!cpuhp_remove_state_nocalls(state)h]h)}(hjh]h!cpuhp_remove_state_nocalls(state)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubj)}(h,cpuhp_remove_state_nocalls_cpuslocked(state)h]h)}(hjh]h,cpuhp_remove_state_nocalls_cpuslocked(state)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubj)}(h cpuhp_remove_multi_state(state) h]h)}(hcpuhp_remove_multi_state(state)h]hcpuhp_remove_multi_state(state)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1jhjhhhhhNubeh}(h]h ]h"]h$]h&]jjuh1jhhhMhjxhhubh)}(h@state参数要么是静态分配的状态,要么是由cpuhp_setup_state*()在动态范围内分配 的状态编号。如果状态在动态范围内,则状态编号被释放,可再次进行动态分配。h]h@state参数要么是静态分配的状态,要么是由cpuhp_setup_state*()在动态范围内分配 的状态编号。如果状态在动态范围内,则状态编号被释放,可再次进行动态分配。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjxhhubh)}(h=这些函数在处理已注册回调的方式上有所不同:h]h=这些函数在处理已注册回调的方式上有所不同:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjxhhubj)}(hX* cpuhp_remove_state_nocalls(), cpuhp_remove_state_nocalls_cpuslocked() 和 cpuhp_remove_multi_state()只删除回调。 * cpuhp_remove_state()删除回调,并调用所有当前状态大于被删除状态的在线CPU的 teardown回调(如果不是NULL)。根据状态阶段,回调要么在当前的CPU上调用 (PREPARE阶段),要么在CPU的热插拔线程中调用每个在线CPU(ONLINE阶段)。 为了完成移除工作,teardown回调不能失败。 h]j)}(hhh](j)}(hwcpuhp_remove_state_nocalls(), cpuhp_remove_state_nocalls_cpuslocked() 和 cpuhp_remove_multi_state()只删除回调。 h]h)}(hvcpuhp_remove_state_nocalls(), cpuhp_remove_state_nocalls_cpuslocked() 和 cpuhp_remove_multi_state()只删除回调。h]hvcpuhp_remove_state_nocalls(), cpuhp_remove_state_nocalls_cpuslocked() 和 cpuhp_remove_multi_state()只删除回调。}(hj$hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj ubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hX`cpuhp_remove_state()删除回调,并调用所有当前状态大于被删除状态的在线CPU的 teardown回调(如果不是NULL)。根据状态阶段,回调要么在当前的CPU上调用 (PREPARE阶段),要么在CPU的热插拔线程中调用每个在线CPU(ONLINE阶段)。 为了完成移除工作,teardown回调不能失败。 h](h)}(hX%cpuhp_remove_state()删除回调,并调用所有当前状态大于被删除状态的在线CPU的 teardown回调(如果不是NULL)。根据状态阶段,回调要么在当前的CPU上调用 (PREPARE阶段),要么在CPU的热插拔线程中调用每个在线CPU(ONLINE阶段)。h]hX%cpuhp_remove_state()删除回调,并调用所有当前状态大于被删除状态的在线CPU的 teardown回调(如果不是NULL)。根据状态阶段,回调要么在当前的CPU上调用 (PREPARE阶段),要么在CPU的热插拔线程中调用每个在线CPU(ONLINE阶段)。}(hj<hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj8ubh)}(h8为了完成移除工作,teardown回调不能失败。h]h8为了完成移除工作,teardown回调不能失败。}(hjJhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj8ubeh}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]jjuh1jhhhMhjubah}(h]h ]h"]h$]h&]uh1jhhhMhjxhhubh)}(h状态移除和回调调用是针对CPU热拔插操作进行序列化的。如果移除函数必须从CPU hotplug 读取锁定区域调用,那么必须使用_cpuslocked()变体。这些函数不能从CPU热插拔的回调中使用。h]h状态移除和回调调用是针对CPU热拔插操作进行序列化的。如果移除函数必须从CPU hotplug 读取锁定区域调用,那么必须使用_cpuslocked()变体。这些函数不能从CPU热插拔的回调中使用。}(hjjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjxhhubh)}(hZ如果一个多实例的状态被移除,那么调用者必须先移除所有的实例。h]hZ如果一个多实例的状态被移除,那么调用者必须先移除所有的实例。}(hjxhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjxhhubeh}(h]id11ah ]h"]移除cpu热拔插状态ah$]h&]uh1jhjPhhhhhMubj)}(hhh](j)}(h多实例状态实例管理h]h多实例状态实例管理}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhMubh)}(hH一旦多实例状态被建立,实例就可以被添加到状态中:h]hH一旦多实例状态被建立,实例就可以被添加到状态中:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubj)}(hX* cpuhp_state_add_instance(state, node) * cpuhp_state_add_instance_nocalls(state, node) h]j)}(hhh](j)}(h%cpuhp_state_add_instance(state, node)h]h)}(hjh]h%cpuhp_state_add_instance(state, node)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(h.cpuhp_state_add_instance_nocalls(state, node) h]h)}(h-cpuhp_state_add_instance_nocalls(state, node)h]h-cpuhp_state_add_instance_nocalls(state, node)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]jjuh1jhhhMhjubah}(h]h ]h"]h$]h&]uh1jhhhMhjhhubh)}(ht@state参数是一个静态分配的状态或由cpuhp_setup_state_multi()在动态范围内分配的状 态编号。h]ht@state参数是一个静态分配的状态或由cpuhp_setup_state_multi()在动态范围内分配的状 态编号。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubh)}(h@node参数是一个指向hlist_node的指针,它被嵌入到实例的数据结构中。这个指针被交给 多实例状态的回调,可以被回调用来通过container_of()检索到实例。h]h@node参数是一个指向hlist_node的指针,它被嵌入到实例的数据结构中。这个指针被交给 多实例状态的回调,可以被回调用来通过container_of()检索到实例。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubh)}(h=这些函数在处理已注册回调的方式上有所不同:h]h=这些函数在处理已注册回调的方式上有所不同:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubj)}(hX}* cpuhp_state_add_instance_nocalls()只将实例添加到多实例状态的节点列表中。 * cpuhp_state_add_instance()为所有当前状态大于@state的在线CPU添加实例并调用与 @state相关的startup回调(如果不是NULL)。该回调只对将要添加的实例进行调用。 根据状态阶段,回调要么在当前的CPU上调用(PREPARE阶段),要么在CPU的热插拔线 程中调用每个在线CPU(ONLINE阶段)。 如果CPU N的回调失败,那么CPU 0 ... N-1的teardown回调被调用以回滚操作,该函数 失败,实例不会被添加到多实例状态的节点列表中。 h]j)}(hhh](j)}(h\cpuhp_state_add_instance_nocalls()只将实例添加到多实例状态的节点列表中。 h]h)}(h[cpuhp_state_add_instance_nocalls()只将实例添加到多实例状态的节点列表中。h]h[cpuhp_state_add_instance_nocalls()只将实例添加到多实例状态的节点列表中。}(hj$hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj ubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hXcpuhp_state_add_instance()为所有当前状态大于@state的在线CPU添加实例并调用与 @state相关的startup回调(如果不是NULL)。该回调只对将要添加的实例进行调用。 根据状态阶段,回调要么在当前的CPU上调用(PREPARE阶段),要么在CPU的热插拔线 程中调用每个在线CPU(ONLINE阶段)。 如果CPU N的回调失败,那么CPU 0 ... N-1的teardown回调被调用以回滚操作,该函数 失败,实例不会被添加到多实例状态的节点列表中。 h](h)}(hXdcpuhp_state_add_instance()为所有当前状态大于@state的在线CPU添加实例并调用与 @state相关的startup回调(如果不是NULL)。该回调只对将要添加的实例进行调用。 根据状态阶段,回调要么在当前的CPU上调用(PREPARE阶段),要么在CPU的热插拔线 程中调用每个在线CPU(ONLINE阶段)。h]hXdcpuhp_state_add_instance()为所有当前状态大于@state的在线CPU添加实例并调用与 @state相关的startup回调(如果不是NULL)。该回调只对将要添加的实例进行调用。 根据状态阶段,回调要么在当前的CPU上调用(PREPARE阶段),要么在CPU的热插拔线 程中调用每个在线CPU(ONLINE阶段)。}(hj<hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj8ubh)}(h如果CPU N的回调失败,那么CPU 0 ... N-1的teardown回调被调用以回滚操作,该函数 失败,实例不会被添加到多实例状态的节点列表中。h]h如果CPU N的回调失败,那么CPU 0 ... N-1的teardown回调被调用以回滚操作,该函数 失败,实例不会被添加到多实例状态的节点列表中。}(hjJhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj8ubeh}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]jjuh1jhhhMhjubah}(h]h ]h"]h$]h&]uh1jhhhMhjhhubh)}(hL要从状态的节点列表中删除一个实例,可以使用这些函数:h]hL要从状态的节点列表中删除一个实例,可以使用这些函数:}(hjjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubj)}(h^* cpuhp_state_remove_instance(state, node) * cpuhp_state_remove_instance_nocalls(state, node) h]j)}(hhh](j)}(h(cpuhp_state_remove_instance(state, node)h]h)}(hjh]h(cpuhp_state_remove_instance(state, node)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1jhj|ubj)}(h1cpuhp_state_remove_instance_nocalls(state, node) h]h)}(h0cpuhp_state_remove_instance_nocalls(state, node)h]h0cpuhp_state_remove_instance_nocalls(state, node)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1jhj|ubeh}(h]h ]h"]h$]h&]jjuh1jhhhMhjxubah}(h]h ]h"]h$]h&]uh1jhhhMhjhhubh)}(h9参数与上述cpuhp_state_add_instance*()变体相同。h]h9参数与上述cpuhp_state_add_instance*()变体相同。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubh)}(h=这些函数在处理已注册回调的方式上有所不同:h]h=这些函数在处理已注册回调的方式上有所不同:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubj)}(hX* cpuhp_state_remove_instance_nocalls()只从状态的节点列表中删除实例。 * cpuhp_state_remove_instance()删除实例并调用与@state相关的回调(如果不是NULL), 用于所有当前状态大于@state的在线CPU。 该回调只对将要被移除的实例进行调用。 根据状态阶段,回调要么在当前的CPU上调用(PREPARE阶段),要么在CPU的热插拔 线程中调用每个在线CPU(ONLINE阶段)。 为了完成移除工作,teardown回调不能失败。 h]j)}(hhh](j)}(hScpuhp_state_remove_instance_nocalls()只从状态的节点列表中删除实例。 h]h)}(hRcpuhp_state_remove_instance_nocalls()只从状态的节点列表中删除实例。h]hRcpuhp_state_remove_instance_nocalls()只从状态的节点列表中删除实例。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubah}(h]h ]h"]h$]h&]uh1jhjubj)}(hXcpuhp_state_remove_instance()删除实例并调用与@state相关的回调(如果不是NULL), 用于所有当前状态大于@state的在线CPU。 该回调只对将要被移除的实例进行调用。 根据状态阶段,回调要么在当前的CPU上调用(PREPARE阶段),要么在CPU的热插拔 线程中调用每个在线CPU(ONLINE阶段)。 为了完成移除工作,teardown回调不能失败。 h](h)}(hXjcpuhp_state_remove_instance()删除实例并调用与@state相关的回调(如果不是NULL), 用于所有当前状态大于@state的在线CPU。 该回调只对将要被移除的实例进行调用。 根据状态阶段,回调要么在当前的CPU上调用(PREPARE阶段),要么在CPU的热插拔 线程中调用每个在线CPU(ONLINE阶段)。h]hXjcpuhp_state_remove_instance()删除实例并调用与@state相关的回调(如果不是NULL), 用于所有当前状态大于@state的在线CPU。 该回调只对将要被移除的实例进行调用。 根据状态阶段,回调要么在当前的CPU上调用(PREPARE阶段),要么在CPU的热插拔 线程中调用每个在线CPU(ONLINE阶段)。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubh)}(h8为了完成移除工作,teardown回调不能失败。h]h8为了完成移除工作,teardown回调不能失败。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjubeh}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]jjuh1jhhhMhjubah}(h]h ]h"]h$]h&]uh1jhhhMhjhhubh)}(h节点列表的添加/删除操作和回调调用是针对CPU热拔插操作进行序列化。这些函数不能在 CPU hotplug回调和CPU hotplug读取锁定区域内使用。h]h节点列表的添加/删除操作和回调调用是针对CPU热拔插操作进行序列化。这些函数不能在 CPU hotplug回调和CPU hotplug读取锁定区域内使用。}(hj'hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubeh}(h]id12ah ]h"]多实例状态实例管理ah$]h&]uh1jhjPhhhhhMubj)}(hhh](j)}(h样例h]h样例}(hj@hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj=hhhhhMubh)}(ha在STARTING阶段设置和取消静态分配的状态,以获取上线和下线操作的通知::h]h`在STARTING阶段设置和取消静态分配的状态,以获取上线和下线操作的通知:}(hjNhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj=hhubj)}(hret = cpuhp_setup_state(CPUHP_SUBSYS_STARTING, "subsys:starting", subsys_cpu_starting, subsys_cpu_dying); if (ret < 0) return ret; .... cpuhp_remove_state(CPUHP_SUBSYS_STARTING);h]hret = cpuhp_setup_state(CPUHP_SUBSYS_STARTING, "subsys:starting", subsys_cpu_starting, subsys_cpu_dying); if (ret < 0) return ret; .... cpuhp_remove_state(CPUHP_SUBSYS_STARTING);}hj\sbah}(h]h ]h"]h$]h&]jjuh1jhhhMhj=hhubh)}(hV在ONLINE阶段设置和取消动态分配的状态,以获取下线操作的通知::h]hU在ONLINE阶段设置和取消动态分配的状态,以获取下线操作的通知:}(hjjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj=hhubj)}(hstate = cpuhp_setup_state(CPUHP_ONLINE_DYN, "subsys:offline", NULL, subsys_cpu_offline); if (state < 0) return state; .... cpuhp_remove_state(state);h]hstate = cpuhp_setup_state(CPUHP_ONLINE_DYN, "subsys:offline", NULL, subsys_cpu_offline); if (state < 0) return state; .... cpuhp_remove_state(state);}hjxsbah}(h]h ]h"]h$]h&]jjuh1jhhhMhj=hhubh)}(ht在ONLINE阶段设置和取消动态分配的状态,以获取有关上线操作的通知,而无需调用回调::h]hs在ONLINE阶段设置和取消动态分配的状态,以获取有关上线操作的通知,而无需调用回调:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj=hhubj)}(hstate = cpuhp_setup_state_nocalls(CPUHP_ONLINE_DYN, "subsys:online", subsys_cpu_online, NULL); if (state < 0) return state; .... cpuhp_remove_state_nocalls(state);h]hstate = cpuhp_setup_state_nocalls(CPUHP_ONLINE_DYN, "subsys:online", subsys_cpu_online, NULL); if (state < 0) return state; .... cpuhp_remove_state_nocalls(state);}hjsbah}(h]h ]h"]h$]h&]jjuh1jhhhM hj=hhubh)}(hq在ONLINE阶段设置、使用和取消动态分配的多实例状态,以获得上线和下线操作的通知::h]hp在ONLINE阶段设置、使用和取消动态分配的多实例状态,以获得上线和下线操作的通知:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj=hhubj)}(hXstate = cpuhp_setup_state_multi(CPUHP_ONLINE_DYN, "subsys:online", subsys_cpu_online, subsys_cpu_offline); if (state < 0) return state; .... ret = cpuhp_state_add_instance(state, &inst1->node); if (ret) return ret; .... ret = cpuhp_state_add_instance(state, &inst2->node); if (ret) return ret; .... cpuhp_remove_instance(state, &inst1->node); .... cpuhp_remove_instance(state, &inst2->node); .... remove_multi_state(state);h]hXstate = cpuhp_setup_state_multi(CPUHP_ONLINE_DYN, "subsys:online", subsys_cpu_online, subsys_cpu_offline); if (state < 0) return state; .... ret = cpuhp_state_add_instance(state, &inst1->node); if (ret) return ret; .... ret = cpuhp_state_add_instance(state, &inst2->node); if (ret) return ret; .... cpuhp_remove_instance(state, &inst1->node); .... cpuhp_remove_instance(state, &inst2->node); .... remove_multi_state(state);}hjsbah}(h]h ]h"]h$]h&]jjuh1jhhhMhj=hhubeh}(h]id13ah ]h"]样例ah$]h&]uh1jhjPhhhhhMubeh}(h]cpuapiah ]h"]cpu热插拔apiah$]h&]uh1jhjhhhhhKubj)}(hhh](j)}(h测试热拔插状态h]h测试热拔插状态}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhM$ubh)}(hX<验证自定义状态是否按预期工作的一个方法是关闭一个CPU,然后再把它上线。也可以把CPU放到某 些状态(例如 ``CPUHP_AP_ONLINE`` ),然后再回到 ``CPUHP_ONLINE`` 。这将模拟在 ``CPUHP_AP_ONLINE`` 之后的一个状态出现错误,从而导致回滚到在线状态。h](h验证自定义状态是否按预期工作的一个方法是关闭一个CPU,然后再把它上线。也可以把CPU放到某 些状态(例如 }(hjhhhNhNubj)}(h``CPUHP_AP_ONLINE``h]hCPUHP_AP_ONLINE}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh ),然后再回到 }(hjhhhNhNubj)}(h``CPUHP_ONLINE``h]h CPUHP_ONLINE}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 。这将模拟在 }(hjhhhNhNubj)}(h``CPUHP_AP_ONLINE``h]hCPUHP_AP_ONLINE}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubhI 之后的一个状态出现错误,从而导致回滚到在线状态。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM&hjhhubh)}(hR所有注册的状态都被列举在 ``/sys/devices/system/cpu/hotplug/states`` ::h](h%所有注册的状态都被列举在 }(hj#hhhNhNubj)}(h*``/sys/devices/system/cpu/hotplug/states``h]h&/sys/devices/system/cpu/hotplug/states}(hj+hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj#ubeh}(h]h ]h"]h$]h&]uh1hhhhM*hjhhubj)}(hX$ tail /sys/devices/system/cpu/hotplug/states 138: mm/vmscan:online 139: mm/vmstat:online 140: lib/percpu_cnt:online 141: acpi/cpu-drv:online 142: base/cacheinfo:online 143: virtio/net:online 144: x86/mce:online 145: printk:online 168: sched:active 169: onlineh]hX$ tail /sys/devices/system/cpu/hotplug/states 138: mm/vmscan:online 139: mm/vmstat:online 140: lib/percpu_cnt:online 141: acpi/cpu-drv:online 142: base/cacheinfo:online 143: virtio/net:online 144: x86/mce:online 145: printk:online 168: sched:active 169: online}hj?sbah}(h]h ]h"]h$]h&]jjuh1jhhhM,hjhhubh)}(hW要将CPU4回滚到 ``lib/percpu_cnt:online`` ,再回到在线状态,只需发出::h](h要将CPU4回滚到 }(hjMhhhNhNubj)}(h``lib/percpu_cnt:online``h]hlib/percpu_cnt:online}(hjUhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjMubh) ,再回到在线状态,只需发出:}(hjMhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhM8hjhhubj)}(h$ cat /sys/devices/system/cpu/cpu4/hotplug/state 169 $ echo 140 > /sys/devices/system/cpu/cpu4/hotplug/target $ cat /sys/devices/system/cpu/cpu4/hotplug/state 140h]h$ cat /sys/devices/system/cpu/cpu4/hotplug/state 169 $ echo 140 > /sys/devices/system/cpu/cpu4/hotplug/target $ cat /sys/devices/system/cpu/cpu4/hotplug/state 140}hjmsbah}(h]h ]h"]h$]h&]jjuh1jhhhM:hjhhubh)}(hS需要注意的是,状态140的清除回调已经被调用。现在重新上线::h]hR需要注意的是,状态140的清除回调已经被调用。现在重新上线:}(hj{hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM@hjhhubj)}(hm$ echo 169 > /sys/devices/system/cpu/cpu4/hotplug/target $ cat /sys/devices/system/cpu/cpu4/hotplug/state 169h]hm$ echo 169 > /sys/devices/system/cpu/cpu4/hotplug/target $ cat /sys/devices/system/cpu/cpu4/hotplug/state 169}hjsbah}(h]h ]h"]h$]h&]jjuh1jhhhMBhjhhubh)}(h5启用追踪事件后,单个步骤也是可见的::h]h4启用追踪事件后,单个步骤也是可见的:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMFhjhhubj)}(hX# TASK-PID CPU# TIMESTAMP FUNCTION # | | | | | bash-394 [001] 22.976: cpuhp_enter: cpu: 0004 target: 140 step: 169 (cpuhp_kick_ap_work) cpuhp/4-31 [004] 22.977: cpuhp_enter: cpu: 0004 target: 140 step: 168 (sched_cpu_deactivate) cpuhp/4-31 [004] 22.990: cpuhp_exit: cpu: 0004 state: 168 step: 168 ret: 0 cpuhp/4-31 [004] 22.991: cpuhp_enter: cpu: 0004 target: 140 step: 144 (mce_cpu_pre_down) cpuhp/4-31 [004] 22.992: cpuhp_exit: cpu: 0004 state: 144 step: 144 ret: 0 cpuhp/4-31 [004] 22.993: cpuhp_multi_enter: cpu: 0004 target: 140 step: 143 (virtnet_cpu_down_prep) cpuhp/4-31 [004] 22.994: cpuhp_exit: cpu: 0004 state: 143 step: 143 ret: 0 cpuhp/4-31 [004] 22.995: cpuhp_enter: cpu: 0004 target: 140 step: 142 (cacheinfo_cpu_pre_down) cpuhp/4-31 [004] 22.996: cpuhp_exit: cpu: 0004 state: 142 step: 142 ret: 0 bash-394 [001] 22.997: cpuhp_exit: cpu: 0004 state: 140 step: 169 ret: 0 bash-394 [005] 95.540: cpuhp_enter: cpu: 0004 target: 169 step: 140 (cpuhp_kick_ap_work) cpuhp/4-31 [004] 95.541: cpuhp_enter: cpu: 0004 target: 169 step: 141 (acpi_soft_cpu_online) cpuhp/4-31 [004] 95.542: cpuhp_exit: cpu: 0004 state: 141 step: 141 ret: 0 cpuhp/4-31 [004] 95.543: cpuhp_enter: cpu: 0004 target: 169 step: 142 (cacheinfo_cpu_online) cpuhp/4-31 [004] 95.544: cpuhp_exit: cpu: 0004 state: 142 step: 142 ret: 0 cpuhp/4-31 [004] 95.545: cpuhp_multi_enter: cpu: 0004 target: 169 step: 143 (virtnet_cpu_online) cpuhp/4-31 [004] 95.546: cpuhp_exit: cpu: 0004 state: 143 step: 143 ret: 0 cpuhp/4-31 [004] 95.547: cpuhp_enter: cpu: 0004 target: 169 step: 144 (mce_cpu_online) cpuhp/4-31 [004] 95.548: cpuhp_exit: cpu: 0004 state: 144 step: 144 ret: 0 cpuhp/4-31 [004] 95.549: cpuhp_enter: cpu: 0004 target: 169 step: 145 (console_cpu_notify) cpuhp/4-31 [004] 95.550: cpuhp_exit: cpu: 0004 state: 145 step: 145 ret: 0 cpuhp/4-31 [004] 95.551: cpuhp_enter: cpu: 0004 target: 169 step: 168 (sched_cpu_activate) cpuhp/4-31 [004] 95.552: cpuhp_exit: cpu: 0004 state: 168 step: 168 ret: 0 bash-394 [005] 95.553: cpuhp_exit: cpu: 0004 state: 169 step: 140 ret: 0h]hX# TASK-PID CPU# TIMESTAMP FUNCTION # | | | | | bash-394 [001] 22.976: cpuhp_enter: cpu: 0004 target: 140 step: 169 (cpuhp_kick_ap_work) cpuhp/4-31 [004] 22.977: cpuhp_enter: cpu: 0004 target: 140 step: 168 (sched_cpu_deactivate) cpuhp/4-31 [004] 22.990: cpuhp_exit: cpu: 0004 state: 168 step: 168 ret: 0 cpuhp/4-31 [004] 22.991: cpuhp_enter: cpu: 0004 target: 140 step: 144 (mce_cpu_pre_down) cpuhp/4-31 [004] 22.992: cpuhp_exit: cpu: 0004 state: 144 step: 144 ret: 0 cpuhp/4-31 [004] 22.993: cpuhp_multi_enter: cpu: 0004 target: 140 step: 143 (virtnet_cpu_down_prep) cpuhp/4-31 [004] 22.994: cpuhp_exit: cpu: 0004 state: 143 step: 143 ret: 0 cpuhp/4-31 [004] 22.995: cpuhp_enter: cpu: 0004 target: 140 step: 142 (cacheinfo_cpu_pre_down) cpuhp/4-31 [004] 22.996: cpuhp_exit: cpu: 0004 state: 142 step: 142 ret: 0 bash-394 [001] 22.997: cpuhp_exit: cpu: 0004 state: 140 step: 169 ret: 0 bash-394 [005] 95.540: cpuhp_enter: cpu: 0004 target: 169 step: 140 (cpuhp_kick_ap_work) cpuhp/4-31 [004] 95.541: cpuhp_enter: cpu: 0004 target: 169 step: 141 (acpi_soft_cpu_online) cpuhp/4-31 [004] 95.542: cpuhp_exit: cpu: 0004 state: 141 step: 141 ret: 0 cpuhp/4-31 [004] 95.543: cpuhp_enter: cpu: 0004 target: 169 step: 142 (cacheinfo_cpu_online) cpuhp/4-31 [004] 95.544: cpuhp_exit: cpu: 0004 state: 142 step: 142 ret: 0 cpuhp/4-31 [004] 95.545: cpuhp_multi_enter: cpu: 0004 target: 169 step: 143 (virtnet_cpu_online) cpuhp/4-31 [004] 95.546: cpuhp_exit: cpu: 0004 state: 143 step: 143 ret: 0 cpuhp/4-31 [004] 95.547: cpuhp_enter: cpu: 0004 target: 169 step: 144 (mce_cpu_online) cpuhp/4-31 [004] 95.548: cpuhp_exit: cpu: 0004 state: 144 step: 144 ret: 0 cpuhp/4-31 [004] 95.549: cpuhp_enter: cpu: 0004 target: 169 step: 145 (console_cpu_notify) cpuhp/4-31 [004] 95.550: cpuhp_exit: cpu: 0004 state: 145 step: 145 ret: 0 cpuhp/4-31 [004] 95.551: cpuhp_enter: cpu: 0004 target: 169 step: 168 (sched_cpu_activate) cpuhp/4-31 [004] 95.552: cpuhp_exit: cpu: 0004 state: 168 step: 168 ret: 0 bash-394 [005] 95.553: cpuhp_exit: cpu: 0004 state: 169 step: 140 ret: 0}hjsbah}(h]h ]h"]h$]h&]jjuh1jhhhMHhjhhubh)}(h可以看到,CPU4一直下降到时间戳22.996,然后又上升到95.552。所有被调用的回调, 包括它们的返回代码都可以在跟踪中看到。h]h可以看到,CPU4一直下降到时间戳22.996,然后又上升到95.552。所有被调用的回调, 包括它们的返回代码都可以在跟踪中看到。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMchjhhubeh}(h]id14ah ]h"]测试热拔插状态ah$]h&]uh1jhjhhhhhM$ubj)}(hhh](j)}(h架构的要求h]h架构的要求}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhMgubh)}(h$需要具备以下功能和配置:h]h$需要具备以下功能和配置:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMihjhhubj)}(hhh](j)}(h@``CONFIG_HOTPLUG_CPU`` 这个配置项需要在Kconfig中启用 h](j)}(h``CONFIG_HOTPLUG_CPU``h]j)}(hjh]hCONFIG_HOTPLUG_CPU}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jhhhMlhjubj)}(hhh]h)}(h(这个配置项需要在Kconfig中启用h]h(这个配置项需要在Kconfig中启用}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMlhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhMlhjubj)}(h.``__cpu_up()`` 调出一个cpu的架构接口 h](j)}(h``__cpu_up()``h]j)}(hj)h]h __cpu_up()}(hj+hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj'ubah}(h]h ]h"]h$]h&]uh1jhhhMohj#ubj)}(hhh]h)}(h调出一个cpu的架构接口h]h调出一个cpu的架构接口}(hjAhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMohj>ubah}(h]h ]h"]h$]h&]uh1jhj#ubeh}(h]h ]h"]h$]h&]uh1jhhhMohjhhubj)}(h``__cpu_disable()`` 关闭CPU的架构接口,在此程序返回后,内核不能再处理任何中断。这包括定时器的关闭。 h](j)}(h``__cpu_disable()``h]j)}(hjah]h__cpu_disable()}(hjchhhNhNubah}(h]h ]h"]h$]h&]uh1jhj_ubah}(h]h ]h"]h$]h&]uh1jhhhMrhj[ubj)}(hhh]h)}(hu关闭CPU的架构接口,在此程序返回后,内核不能再处理任何中断。这包括定时器的关闭。h]hu关闭CPU的架构接口,在此程序返回后,内核不能再处理任何中断。这包括定时器的关闭。}(hjyhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMrhjvubah}(h]h ]h"]h$]h&]uh1jhj[ubeh}(h]h ]h"]h$]h&]uh1jhhhMrhjhhubj)}(hXP``__cpu_die()`` 这实际上是为了确保CPU的死亡。实际上,看看其他架构中实现CPU热拔插的一些示例代 码。对于那个特定的架构,处理器被从 ``idle()`` 循环中拿下来。 ``__cpu_die()`` 通常会等待一些per_cpu状态的设置,以确保处理器的死亡例程被调用来保持活跃。 h](j)}(h``__cpu_die()``h]j)}(hjh]h __cpu_die()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jhhhMwhjubj)}(hhh]h)}(hX?这实际上是为了确保CPU的死亡。实际上,看看其他架构中实现CPU热拔插的一些示例代 码。对于那个特定的架构,处理器被从 ``idle()`` 循环中拿下来。 ``__cpu_die()`` 通常会等待一些per_cpu状态的设置,以确保处理器的死亡例程被调用来保持活跃。h](h这实际上是为了确保CPU的死亡。实际上,看看其他架构中实现CPU热拔插的一些示例代 码。对于那个特定的架构,处理器被从 }(hjhhhNhNubj)}(h ``idle()``h]hidle()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 循环中拿下来。 }(hjhhhNhNubj)}(h``__cpu_die()``h]h __cpu_die()}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubhk 通常会等待一些per_cpu状态的设置,以确保处理器的死亡例程被调用来保持活跃。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhMuhjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhMwhjhhubeh}(h]h ]h"]h$]h&]uh1jhjhhhhhNubeh}(h]id15ah ]h"]架构的要求ah$]h&]uh1jhjhhhhhMgubj)}(hhh](j)}(h用户空间通知h]h用户空间通知}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjhhhhhMzubh)}(hR在CPU成功上线或下线后,udev事件被发送。一个udev规则,比如::h]hQ在CPU成功上线或下线后,udev事件被发送。一个udev规则,比如:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhM|hjhhubj)}(hhSUBSYSTEM=="cpu", DRIVERS=="processor", DEVPATH=="/devices/system/cpu/*", RUN+="the_hotplug_receiver.sh"h]hhSUBSYSTEM=="cpu", DRIVERS=="processor", DEVPATH=="/devices/system/cpu/*", RUN+="the_hotplug_receiver.sh"}hjsbah}(h]h ]h"]h$]h&]jjuh1jhhhM~hjhhubh)}(h2将接收所有事件。一个像这样的脚本::h]h1将接收所有事件。一个像这样的脚本:}(hj*hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubj)}(h#!/bin/sh if [ "${ACTION}" = "offline" ] then echo "CPU ${DEVPATH##*/} offline" elif [ "${ACTION}" = "online" ] then echo "CPU ${DEVPATH##*/} online" fih]h#!/bin/sh if [ "${ACTION}" = "offline" ] then echo "CPU ${DEVPATH##*/} offline" elif [ "${ACTION}" = "online" ] then echo "CPU ${DEVPATH##*/} online" fi}hj8sbah}(h]h ]h"]h$]h&]jjuh1jhhhMhjhhubh)}(h!可以进一步处理该事件。h]h!可以进一步处理该事件。}(hjFhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhjhhubeh}(h]id16ah ]h"]用户空间通知ah$]h&]uh1jhjhhhhhMzubj)}(hhh](j)}(h内核内联文档参考h]h内核内联文档参考}(hj_hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj\hhhhhMubh)}(h该API在以下内核代码中:h]h该API在以下内核代码中:}(hjmhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj\hhubh)}(hinclude/linux/cpuhotplug.hh]hinclude/linux/cpuhotplug.h}(hj{hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhMhj\hhubeh}(h]id17ah ]h"]内核内联文档参考ah$]h&]uh1jhjhhhhhMubeh}(h](cpujeh ]h"](内核中的cpu热拔插cn_core_api_cpu_hotplugeh$]h&]uh1jhhhhhhhKexpect_referenced_by_name}jjsexpect_referenced_by_id}jjsubeh}(h]h ]h"]h$]h&]sourcehuh1hcurrent_sourceN current_lineNsettingsdocutils.frontendValues)}(jN generatorN datestampN source_linkN source_urlN toc_backlinksj` footnote_backlinksK sectnum_xformKstrip_commentsNstrip_elements_with_classesN strip_classesN report_levelK halt_levelKexit_status_levelKdebugNwarning_streamN tracebackinput_encoding utf-8-siginput_encoding_error_handlerstrictoutput_encodingutf-8output_encoding_error_handlerjerror_encodingutf-8error_encoding_error_handlerbackslashreplace language_codeenrecord_dependenciesNconfigN id_prefixhauto_id_prefixid dump_settingsNdump_internalsNdump_transformsNdump_pseudo_xmlNexpose_internalsNstrict_visitorN_disable_configN_sourceh، _destinationN _config_files]7/var/lib/git/docbuild/linux/Documentation/docutils.confafile_insertion_enabled raw_enabledKline_length_limitM'pep_referencesN pep_base_urlhttps://peps.python.org/pep_file_url_templatepep-%04drfc_referencesN rfc_base_url&https://datatracker.ietf.org/doc/html/ tab_widthKtrim_footnote_reference_spacesyntax_highlightlong smart_quotessmartquotes_locales]character_level_inline_markupdoctitle_xform docinfo_xformKsectsubtitle_xform image_loadinglinkembed_stylesheetcloak_email_addressessection_self_linkenvNubreporterNindirect_targets]substitution_defs}substitution_names}refnames}refids}j]jasnameids}(jjjjjjjMjJjjjDjAjMjJjEjBjjj j j j jc j` jujrjjj:j7jjjjjjjYjVjju nametypes}(jjjjMjjDjMjEjj j jc jujj:jjjjYjuh}(jjjjjjjJjjjPjAjjJjGjBjXjjPj jaj j j` j jrjf jjxj7jjj=jjjjjVjjj\u footnote_refs} citation_refs} autofootnotes]autofootnote_refs]symbol_footnotes]symbol_footnote_refs] footnotes] citations]autofootnote_startKsymbol_footnote_startK id_counter collectionsCounter}jKsRparse_messages]transform_messages]hsystem_message)}(hhh]h)}(hhh]h=Hyperlink target "cn-core-api-cpu-hotplug" is not referenced.}hj*sbah}(h]h ]h"]h$]h&]uh1hhj'ubah}(h]h ]h"]h$]h&]levelKtypeINFOsourceh،lineKuh1j%uba transformerN include_log]9Documentation/translations/zh_CN/core-api/cpu_hotplug.rst(NNNNta decorationNhhub.