diff options
Diffstat (limited to 'Documentation/translations/zh_CN')
28 files changed, 1848 insertions, 90 deletions
diff --git a/Documentation/translations/zh_CN/admin-guide/README.rst b/Documentation/translations/zh_CN/admin-guide/README.rst index 1bdafdc4c8e2..82e628b77efd 100644 --- a/Documentation/translations/zh_CN/admin-guide/README.rst +++ b/Documentation/translations/zh_CN/admin-guide/README.rst @@ -224,7 +224,7 @@ Linux内核6.x版本 <http://kernel.org/> 编译内核 --------- - - 确保您至少有gcc 5.1可用。 + - 确保您至少有gcc 8.1可用。 有关更多信息,请参阅 :ref:`Documentation/process/changes.rst <changes>` 。 - 执行 ``make`` 来创建压缩内核映像。如果您安装了lilo以适配内核makefile, diff --git a/Documentation/translations/zh_CN/admin-guide/bug-hunting.rst b/Documentation/translations/zh_CN/admin-guide/bug-hunting.rst index c3f6a83294dc..4b3432753eb9 100644 --- a/Documentation/translations/zh_CN/admin-guide/bug-hunting.rst +++ b/Documentation/translations/zh_CN/admin-guide/bug-hunting.rst @@ -188,7 +188,7 @@ objdump 编行。如果没有调试符号,您将看到所示例程的汇编程序代码,但是如果内核有调试 符号,C代码也将可见(调试符号可以在内核配置菜单的hacking项中启用)。例如:: - $ objdump -r -S -l --disassemble net/dccp/ipv4.o + $ objdump -r -S -l --disassemble net/ipv4/tcp.o .. note:: diff --git a/Documentation/translations/zh_CN/core-api/irq/irq-domain.rst b/Documentation/translations/zh_CN/core-api/irq/irq-domain.rst index 9174fce12c1b..4a2d3b27aa4d 100644 --- a/Documentation/translations/zh_CN/core-api/irq/irq-domain.rst +++ b/Documentation/translations/zh_CN/core-api/irq/irq-domain.rst @@ -60,8 +60,6 @@ irq_domain和一个hwirq号作为参数。 如果hwirq的映射还不存在, - irq_find_mapping()返回给定域和hwirq的Linux IRQ号,如果没有映射则返回0。 -- irq_linear_revmap()现与irq_find_mapping()相同,已被废弃。 - - generic_handle_domain_irq()处理一个由域和hwirq号描述的中断。 请注意,irq域的查找必须发生在与RCU读临界区兼容的上下文中。 @@ -83,7 +81,6 @@ irq_domain映射的类型 :: - irq_domain_add_linear() irq_domain_create_linear() 线性反向映射维护了一个固定大小的表,该表以hwirq号为索引。 当一个hwirq被映射 @@ -104,7 +101,6 @@ irq_domain_add_linear()和irq_domain_create_linear()在功能上是等价的, :: - irq_domain_add_tree() irq_domain_create_tree() irq_domain维护着从hwirq号到Linux IRQ的radix的树状映射。 当一个hwirq被映射时, @@ -124,7 +120,7 @@ irq_domain_add_tree()和irq_domain_create_tree()在功能上是等价的,除 :: - irq_domain_add_nomap() + irq_domain_create_nomap() 当硬件中的hwirq号是可编程的时候,就可以采用无映射类型。 在这种情况下,最好将 Linux IRQ号编入硬件本身,这样就不需要映射了。 调用irq_create_direct_mapping() @@ -138,8 +134,6 @@ Linux IRQ号编入硬件本身,这样就不需要映射了。 调用irq_create :: - irq_domain_add_simple() - irq_domain_add_legacy() irq_domain_create_simple() irq_domain_create_legacy() diff --git a/Documentation/translations/zh_CN/core-api/memory-hotplug.rst b/Documentation/translations/zh_CN/core-api/memory-hotplug.rst index 9b2841fb9a5f..c2a4122ae221 100644 --- a/Documentation/translations/zh_CN/core-api/memory-hotplug.rst +++ b/Documentation/translations/zh_CN/core-api/memory-hotplug.rst @@ -62,7 +62,6 @@ memory_notify结构体的指针:: struct memory_notify { unsigned long start_pfn; unsigned long nr_pages; - int status_change_nid_normal; int status_change_nid; } @@ -70,8 +69,6 @@ memory_notify结构体的指针:: - nr_pages是在线/离线内存的页数。 -- status_change_nid_normal是当nodemask的N_NORMAL_MEMORY被设置/清除时设置节 - 点id,如果是-1,则nodemask状态不改变。 - status_change_nid是当nodemask的N_MEMORY被(将)设置/清除时设置的节点id。这 意味着一个新的(没上线的)节点通过联机获得新的内存,而一个节点失去了所有的内 diff --git a/Documentation/translations/zh_CN/core-api/printk-formats.rst b/Documentation/translations/zh_CN/core-api/printk-formats.rst index bd36d35eba4e..96a917ecc93f 100644 --- a/Documentation/translations/zh_CN/core-api/printk-formats.rst +++ b/Documentation/translations/zh_CN/core-api/printk-formats.rst @@ -523,9 +523,8 @@ clk结构体 :: %pC pll1 - %pCn pll1 -用于打印clk结构。%pC 和 %pCn 打印时钟的名称(通用时钟框架)或唯一的32位 +用于打印clk结构。%pC 打印时钟的名称(通用时钟框架)或唯一的32位 ID(传统时钟框架)。 通过引用传递。 diff --git a/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst b/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst index b1bec219912d..d9477ccea98f 100644 --- a/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst +++ b/Documentation/translations/zh_CN/core-api/symbol-namespaces.rst @@ -14,18 +14,8 @@ 本文档描述了如何使用符号命名空间来构造通过EXPORT_SYMBOL()系列宏导出的内核内符号的导出面。 -.. 目录 - - === 1 简介 - === 2 如何定义符号命名空间 - --- 2.1 使用EXPORT_SYMBOL宏 - --- 2.2 使用DEFAULT_SYMBOL_NAMESPACE定义 - === 3 如何使用命名空间中导出的符号 - === 4 加载使用命名空间符号的模块 - === 5 自动创建MODULE_IMPORT_NS声明 - -1. 简介 -======= +简介 +==== 符号命名空间已经被引入,作为构造内核内API的导出面的一种手段。它允许子系统维护者将 他们导出的符号划分进独立的命名空间。这对于文档的编写非常有用(想想SUBSYSTEM_DEBUG @@ -33,14 +23,14 @@ 的模块必须导入命名空间。否则,内核将根据其配置,拒绝加载该模块或警告说缺少 导入。 -2. 如何定义符号命名空间 -======================= +如何定义符号命名空间 +==================== 符号可以用不同的方法导出到命名空间。所有这些都在改变 EXPORT_SYMBOL 和与之类似的那些宏 被检测到的方式,以创建 ksymtab 条目。 -2.1 使用EXPORT_SYMBOL宏 -======================= +使用EXPORT_SYMBOL宏 +------------------- 除了允许将内核符号导出到内核符号表的宏EXPORT_SYMBOL()和EXPORT_SYMBOL_GPL()之外, 这些宏的变体还可以将符号导出到某个命名空间:EXPORT_SYMBOL_NS() 和 EXPORT_SYMBOL_NS_GPL()。 @@ -54,8 +44,8 @@ 导出时未指明命名空间的符号将指向 ``NULL`` 。如果没有定义命名空间,则默认没有。 ``modpost`` 和kernel/module/main.c分别在构建时或模块加载时使用名称空间。 -2.2 使用DEFAULT_SYMBOL_NAMESPACE定义 -==================================== +使用DEFAULT_SYMBOL_NAMESPACE定义 +-------------------------------- 为一个子系统的所有符号定义命名空间可能会非常冗长,并可能变得难以维护。因此,我 们提供了一个默认定义(DEFAULT_SYMBOL_NAMESPACE),如果设置了这个定义, 它将成 @@ -80,8 +70,8 @@ 应置于相关编译单元中任何 EXPORT_SYMBOL 宏之前 -3. 如何使用命名空间中导出的符号 -=============================== +如何使用命名空间中导出的符号 +============================ 为了使用被导出到命名空间的符号,内核模块需要明确地导入这些命名空间。 否则内核可能会拒绝加载该模块。模块代码需要使用宏MODULE_IMPORT_NS来 @@ -100,11 +90,10 @@ 建议将 MODULE_IMPORT_NS() 语句添加到靠近其他模块元数据定义的地方, -如 MODULE_AUTHOR() 或 MODULE_LICENSE() 。关于自动创建缺失的导入 -语句的方法,请参考第5节。 +如 MODULE_AUTHOR() 或 MODULE_LICENSE() 。 -4. 加载使用命名空间符号的模块 -============================= +加载使用命名空间符号的模块 +========================== 在模块加载时(比如 ``insmod`` ),内核将检查每个从模块中引用的符号是否可 用,以及它可能被导出到的名字空间是否被模块导入。内核的默认行为是拒绝 @@ -113,8 +102,8 @@ EINVAL方式失败。要允许加载不满足这个前提条件的模块,可 设置 MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS=y 将使加载不受影响,但会 发出警告。 -5. 自动创建MODULE_IMPORT_NS声明 -=============================== +自动创建MODULE_IMPORT_NS声明 +============================ 缺少命名空间的导入可以在构建时很容易被检测到。事实上,如果一个模块 使用了一个命名空间的符号而没有导入它,modpost会发出警告。 diff --git a/Documentation/translations/zh_CN/dev-tools/gdb-kernel-debugging.rst b/Documentation/translations/zh_CN/dev-tools/gdb-kernel-debugging.rst index 3c133a918f30..282aacd33442 100644 --- a/Documentation/translations/zh_CN/dev-tools/gdb-kernel-debugging.rst +++ b/Documentation/translations/zh_CN/dev-tools/gdb-kernel-debugging.rst @@ -120,35 +120,31 @@ Kgdb内核调试器、QEMU等虚拟机管理程序或基于JTAG的硬件接口 - 对当前或指定的CPU使用per-cpu函数:: - (gdb) p $lx_per_cpu("runqueues").nr_running + (gdb) p $lx_per_cpu(runqueues).nr_running $3 = 1 - (gdb) p $lx_per_cpu("runqueues", 2).nr_running + (gdb) p $lx_per_cpu(runqueues, 2).nr_running $4 = 0 - 使用container_of查看更多hrtimers信息:: - (gdb) set $next = $lx_per_cpu("hrtimer_bases").clock_base[0].active.next - (gdb) p *$container_of($next, "struct hrtimer", "node") + (gdb) set $leftmost = $lx_per_cpu(hrtimer_bases).clock_base[0].active.rb_root.rb_leftmost + (gdb) p *$container_of($leftmost, "struct hrtimer", "node") $5 = { node = { node = { - __rb_parent_color = 18446612133355256072, - rb_right = 0x0 <irq_stack_union>, - rb_left = 0x0 <irq_stack_union> + __rb_parent_color = 18446612686384860673, + rb_right = 0xffff888231da8b00, + rb_left = 0x0 }, - expires = { - tv64 = 1835268000000 - } + expires = 1228461000000 }, - _softexpires = { - tv64 = 1835268000000 - }, - function = 0xffffffff81078232 <tick_sched_timer>, - base = 0xffff88003fd0d6f0, - state = 1, - start_pid = 0, - start_site = 0xffffffff81055c1f <hrtimer_start_range_ns+20>, - start_comm = "swapper/2\000\000\000\000\000\000" + _softexpires = 1228461000000, + function = 0xffffffff8137ab20 <tick_nohz_handler>, + base = 0xffff888231d9b4c0, + state = 1 '\001', + is_rel = 0 '\000', + is_soft = 0 '\000', + is_hard = 1 '\001' } diff --git a/Documentation/translations/zh_CN/devicetree/overlay-notes.rst b/Documentation/translations/zh_CN/devicetree/overlay-notes.rst index 43e3c0bc5a9f..ba5edd05dc1e 100644 --- a/Documentation/translations/zh_CN/devicetree/overlay-notes.rst +++ b/Documentation/translations/zh_CN/devicetree/overlay-notes.rst @@ -43,10 +43,10 @@ Documentation/devicetree/dynamic-resolution-notes.rst[1]的配套文档。 }; ---- foo.dts --------------------------------------------------------------- -覆盖bar.dts, +覆盖bar.dtso, :: - ---- bar.dts - 按标签覆盖目标位置 ---------------------------- + ---- bar.dtso - 按标签覆盖目标位置 --------------------------- /dts-v1/; /插件/; &ocp { @@ -56,7 +56,7 @@ Documentation/devicetree/dynamic-resolution-notes.rst[1]的配套文档。 ... /* 各种属性和子节点 */ }; }; - ---- bar.dts --------------------------------------------------------------- + ---- bar.dtso -------------------------------------------------------------- 当加载(并按照[1]中描述的方式解决)时,应该产生foo+bar.dts:: @@ -90,9 +90,9 @@ Documentation/devicetree/dynamic-resolution-notes.rst[1]的配套文档。 DT中的适当位置。在这种情况下,可以提供目标路径。通过标签的目标位置的语法是比 较好的,因为不管标签在DT中出现在哪里,覆盖都可以被应用到任何包含标签的基础DT上。 -上面的bar.dts例子被修改为使用目标路径语法,即为:: +上面的bar.dtso例子被修改为使用目标路径语法,即为:: - ---- bar.dts - 通过明确的路径覆盖目标位置 -------------------- + ---- bar.dtso - 通过明确的路径覆盖目标位置 ------------------- /dts-v1/; /插件/; &{/ocp} { @@ -102,7 +102,7 @@ DT中的适当位置。在这种情况下,可以提供目标路径。通过标 ... /* 各种外围设备和子节点 */ } }; - ---- bar.dts --------------------------------------------------------------- + ---- bar.dtso -------------------------------------------------------------- 内核中关于覆盖的API diff --git a/Documentation/translations/zh_CN/driver-api/gpio/index.rst b/Documentation/translations/zh_CN/driver-api/gpio/index.rst index e4d54724a1b5..f64a69f771ca 100644 --- a/Documentation/translations/zh_CN/driver-api/gpio/index.rst +++ b/Documentation/translations/zh_CN/driver-api/gpio/index.rst @@ -42,7 +42,7 @@ ACPI支持 该API在以下内核代码中: -drivers/gpio/gpiolib-acpi.c +drivers/gpio/gpiolib-acpi-core.c 设备树支持 ========== diff --git a/Documentation/translations/zh_CN/how-to.rst b/Documentation/translations/zh_CN/how-to.rst new file mode 100644 index 000000000000..ddd99c0f9b4d --- /dev/null +++ b/Documentation/translations/zh_CN/how-to.rst @@ -0,0 +1,473 @@ +.. SPDX-License-Identifier: GPL-2.0 + +========================== +Linux 内核中文文档翻译规范 +========================== + +修订记录: + - v1.0 2025 年 3 月 28 日,司延腾、慕冬亮共同编写了该规范。 + +制定规范的背景 +============== + +过去几年,在广大社区爱好者的友好合作下,Linux 内核中文文档迎来了蓬勃的发 +展。在翻译的早期,一切都是混乱的,社区对译稿只有一个准确翻译的要求,以鼓 +励更多的开发者参与进来,这是从 0 到 1 的必然过程,所以早期的中文文档目录 +更加具有多样性,不过好在文档不多,维护上并没有过大的压力。 + +然而,世事变幻,不觉有年,现在内核中文文档在前进的道路上越走越远,很多潜 +在的问题逐渐浮出水面,而且随着中文文档数量的增加,翻译更多的文档与提高中 +文文档可维护性之间的矛盾愈发尖锐。由于文档翻译的特殊性,很多开发者并不会 +一直更新文档,如果中文文档落后英文文档太多,文档更新的工作量会远大于重新 +翻译。而且邮件列表中陆续有新的面孔出现,他们那股热情,就像燃烧的火焰,能 +瞬间点燃整个空间,可是他们的补丁往往具有个性,这会给审阅带来了很大的困难, +reviewer 们只能耐心地指导他们如何与社区更好地合作,但是这项工作具有重复 +性,长此以往,会渐渐浇灭 reviewer 审阅的热情。 + +虽然内核文档中已经有了类似的贡献指南,但是缺乏专门针对于中文翻译的,尤其 +是对于新手来说,浏览大量的文档反而更加迷惑,该文档就是为了缓解这一问题而 +编写,目的是为提供给新手一个快速翻译指南。 + +详细的贡献指南:Documentation/translations/zh_CN/process/index.rst。 + +环境搭建 +======== + +工欲善其事必先利其器,如果您目前对内核文档翻译满怀热情,并且会独立地安装 +Linux 发行版和简单地使用 Linux 命令行,那么可以迅速开始了。若您尚不具备该 +能力,很多网站上会有详细的手把手教程,最多一个上午,您应该就能掌握对应技 +能。您需要注意的一点是,请不要使用 root 用户进行后续步骤和文档翻译。 + +拉取开发树 +---------- + +中文文档翻译工作目前独立于 linux-doc 开发树开展,所以您需要拉取该开发树, +打开终端命令行执行:: + + git clone git://git.kernel.org/pub/scm/linux/kernel/git/alexs/linux.git + +如果您遇到网络连接问题,也可以执行以下命令:: + + git clone https://mirrors.hust.edu.cn/git/kernel-doc-zh.git linux + +这是 Alex 开发树的镜像库,每两个小时同步一次上游。如果您了解到更快的 mirror, +请随时 **添加** 。 + +命令执行完毕后,您会在当前目录下得到一个 linux 目录,该目录就是您之后的工作 +仓库,请把它放在一个稳妥的位置。 + +安装文档构建环境 +---------------- + +内核仓库里面提供了一个半自动化脚本,执行该脚本,会检测您的发行版中需要安 +装哪些软件包,请按照命令行提示进行安装,通常您只需要复制命令并执行就行。 +:: + + cd linux + ./scripts/sphinx-pre-install + +以 Fedora 为例,它的输出是这样的:: + + You should run: + + sudo dnf install -y dejavu-sans-fonts dejavu-sans-mono-fonts \ + dejavu-serif-fonts google-noto-sans-cjk-fonts graphviz-gd \ + latexmk librsvg2-tools texlive-anyfontsize texlive-capt-of \ + texlive-collection-fontsrecommended texlive-ctex \ + texlive-eqparbox texlive-fncychap texlive-framed \ + texlive-luatex85 texlive-multirow texlive-needspace \ + texlive-tabulary texlive-threeparttable texlive-upquote \ + texlive-wrapfig texlive-xecjk + + Sphinx needs to be installed either: + 1) via pip/pypi with: + + /usr/bin/python3 -m venv sphinx_latest + . sphinx_latest/bin/activate + pip install -r ./Documentation/sphinx/requirements.txt + + If you want to exit the virtualenv, you can use: + deactivate + + 2) As a package with: + + sudo dnf install -y python3-sphinx + + Please note that Sphinx >= 3.0 will currently produce false-positive + warning when the same name is used for more than one type (functions, + structs, enums,...). This is known Sphinx bug. For more details, see: + https://github.com/sphinx-doc/sphinx/pull/8313 + +请您按照提示复制打印的命令到命令行执行,您必须具备 root 权限才能执行 sudo +开头的命令。**请注意**,最新版本 Sphinx 的文档编译速度有极大提升,强烈建议 +您通过 pip/pypi 安装最新版本 Sphinx。 + +如果您处于一个多用户环境中,为了避免对其他人造成影响,建议您配置单用户 +sphinx 虚拟环境,即只需要执行:: + + /usr/bin/python3 -m venv sphinx_latest + . sphinx_latest/bin/activate + pip install -r ./Documentation/sphinx/requirements.txt + +最后执行以下命令退出虚拟环境:: + + deactivate + +您可以在任何需要的时候再次执行以下命令进入虚拟环境:: + + . sphinx_latest/bin/activate + +进行第一次文档编译 +------------------ + +进入开发树目录:: + + cd linux + +这是一个标准的编译和调试流程,请每次构建时都严格执行:: + + . sphinx_latest/bin/activate + make cleandocs + make htmldocs + deactivate + +检查编译结果 +------------ + +编译输出在 Documentation/output/ 目录下,请用浏览器打开该目录下对应 +的文件进行检查。 + +Git 和邮箱配置 +-------------- + +打开命令行执行:: + + sudo dnf install git-email + vim ~/.gitconfig + +这里是我的一个配置文件示范,请根据您的邮箱域名服务商提供的手册替换到对 +应的字段。 +:: + + [user] + name = Yanteng Si # 这会出现在您的补丁头部签名栏 + email = si.yanteng@linux.dev # 这会出现在您的补丁头部签名栏 + + [sendemail] + from = Yanteng Si <si.yanteng@linux.dev> # 这会出现在您的补丁头部 + smtpencryption = ssl + smtpserver = smtp.migadu.com + smtpuser = si.yanteng@linux.dev + smtppass = <passwd> # 建议使用第三方客户端专用密码 + chainreplyto = false + smtpserverport = 465 + +关于邮件客户端的配置,请查阅 Documentation/translations/zh_CN/process/email-clients.rst。 + +开始翻译文档 +============ + +文档索引结构 +------------ + +目前中文文档是在 Documentation/translations/zh_CN/ 目录下进行,该 +目录结构最终会与 Documentation/ 结构一致,所以您只需要将您感兴趣的英文 +文档文件和对应的 index.rst 复制到 zh_CN 目录下对应的位置,然后修改更 +上一级的 index 即可开始您的翻译。 + +为了保证翻译的文档补丁被顺利合并,不建议多人同时翻译一个目录,因为这会 +造成补丁之间互相依赖,往往会导致一部分补丁被合并,另一部分产生冲突。 + +如果实在无法避免两个人同时对一个目录进行翻译的情况,请将补丁制作进一个补 +丁集。但是不推荐刚开始就这么做,因为经过实践,在没有指导的情况下,新手很 +难一次处理好这个补丁集。 + +请执行以下命令,新建开发分支:: + + git checkout docs-next + git checkout -b my-trans + +译文格式要求 +------------ + + - 每行长度最多不超过 40 个字符 + - 每行长度请保持一致 + - 标题的下划线长度请按照一个英文一个字符、一个中文两个字符与标题对齐 + - 其它的修饰符请与英文文档保持一致 + +此外在译文的头部,您需要插入以下内容:: + + .. SPDX-License-Identifier: GPL-2.0 + .. include:: ../disclaimer-zh_CN.rst #您需要了解该文件的路径,根 + 据您实际翻译的文档灵活调整 + + :Original: Documentation/xxx/xxx.rst #替换为您翻译的英文文档路径 + + :翻译: + + 司延腾 Yanteng Si <si.yanteng@linux.dev> #替换为您自己的联系方式 + +翻译技巧 +-------- + +中文文档有每行 40 字符限制,因为一个中文字符等于 2 个英文字符。但是社区并 +没有那么严格,一个诀窍是将您的翻译的内容与英文原文的每行长度对齐即可,这样, +您也不必总是检查有没有超限。 + +如果您的英文阅读能力有限,可以考虑使用辅助翻译工具,例如 deepseek。但是您 +必须仔细地打磨,使译文达到“信达雅”的标准。 + +**请注意** 社区不接受纯机器翻译的文档,社区工作建立在信任的基础上,请认真对待。 + +编译和检查 +---------- + +请执行:: + + . sphinx_latest/bin/activate + make cleandocs + make htmldocs + +解决与您翻译的文档相关的 warning 和 error,然后执行:: + + make cleandocs #该步骤不能省略,否则可能不会再次输出真实存在的警告 + make htmldocs + deactivate + +进入 output 目录用浏览器打开您翻译的文档,检查渲染的页面是否正常,如果正常, +继续进行后续步骤,否则请尝试解决。 + +制作补丁 +======== + +提交改动 +-------- + +执行以下命令,在弹出的交互式页面中填写必要的信息。 +:: + + git add . + git commit -s -v + +请参考以下信息进行输入:: + + docs/zh_CN: Add self-protection index Chinese translation + + Translate .../security/self-protection.rst into Chinese. + + Update the translation through commit b080e52110ea + ("docs: update self-protection __ro_after_init status") + # 请执行 git log --oneline <您翻译的英文文档路径>,并替换上述内容 + + Signed-off-by: Yanteng Si <si.yanteng@linux.dev> + # 如果您前面的步骤正确执行,该行会自动显示,否则请检查 gitconfig 文件 + +保存并退出。 + +**请注意** 以上四行,缺少任何一行,您都将会在第一轮审阅后返工,如果您需要一个 +更加明确的示例,请对 zh_CN 目录执行 git log。 + +导出补丁和制作封面 +------------------ + +这个时候,可以导出补丁,做发送邮件列表最后的准备了。命令行执行:: + + git format-patch -N + # N 要替换为补丁数量,一般 N 大于等于 1 + +然后命令行会输出类似下面的内容:: + + 0001-docs-zh_CN-add-xxxxxxxx.patch + 0002-docs-zh_CN-add-xxxxxxxx.patch + …… + +测试补丁 +-------- + +内核提供了一个补丁检测脚本,请执行:: + + ./scripts/checkpatch.pl *.patch + +参考脚本输出,解决掉所有的 error 和 warning,通常情况下,只有下面这个 +warning 不需要解决:: + + WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? + +一个简单的解决方法是一次只检查一个补丁,然后打上该补丁,直接对译文进行修改, +然后执行以下命令为补丁追加更改:: + + git checkout docs-next + git checkout -b test-trans-new + git am 0001-xxxxx.patch + ./scripts/checkpatch.pl 0001-xxxxx.patch + # 直接修改您的翻译 + git add . + git am --amend + # 保存退出 + git am 0002-xxxxx.patch + …… + +重新导出再次检测,重复这个过程,直到处理完所有的补丁。 + +最后,如果检测时没有 warning 和 error 需要被处理或者您只有一个补丁,请跳 +过下面这个步骤,否则请重新导出补丁制作封面:: + + git format-patch -N --cover-letter --thread=shallow + # N 要替换为补丁数量,一般 N 大于 1 + +然后命令行会输出类似下面的内容:: + + 0000-cover-letter.patch + 0001-docs-zh_CN-add-xxxxxxxx.patch + 0002-docs-zh_CN-add-xxxxxxxx.patch + …… + +您需要用编辑器打开 0 号补丁,修改两处内容:: + + vim 0000-cover-letter.patch + + ... + Subject: [PATCH 0/N] *** SUBJECT HERE *** #修改该字段,概括您的补丁集都做了哪些事情 + + *** BLURB HERE *** #修改该字段,详细描述您的补丁集做了哪些事情 + + Yanteng Si (1): + docs/zh_CN: add xxxxx + ... + +如果您只有一个补丁,则可以不制作封面,即 0 号补丁,只需要执行:: + + git format-patch -1 + +把补丁提交到邮件列表 +==================== + +恭喜您,您的文档翻译现在可以提交到邮件列表了。 + +获取维护者和审阅者邮箱以及邮件列表地址 +-------------------------------------- + +内核提供了一个自动化脚本工具,请执行:: + + ./scripts/get_maintainer.pl *.patch + +将输出的邮箱地址保存下来。 + +将补丁提交到邮件列表 +-------------------- + +打开上面您保存的邮件地址,执行:: + + git send-email *.patch --to <maintainer email addr> --cc <others addr> + # 一个 to 对应一个地址,一个 cc 对应一个地址,有几个就写几个 + +执行该命令时,请确保网络通常,邮件发送成功一般会返回 250。 + +您可以先发送给自己,尝试发出的 patch 是否可以用 'git am' 工具正常打上。 +如果检查正常, 您就可以放心的发送到社区评审了。 + +如果该步骤被中断,您可以检查一下,继续用上条命令发送失败的补丁,一定不要再 +次发送已经发送成功的补丁。 + +积极参与审阅过程并迭代补丁 +========================== + +补丁提交到邮件列表并不代表万事大吉,您还需要积极回复 maintainer 和 +reviewer 的评论,做到每条都有回复,每个回复都落实到位。 + +如何回复评论 +------------ + + - 请先将您的邮箱客户端信件回复修改为 **纯文本** 格式,并去除所有签名,尤其是 + 企业邮箱。 + - 然后点击回复按钮,并将要回复的邮件带入, + - 在第一条评论行尾换行,输入您的回复 + - 在第二条评论行尾换行,输入您的回复 + - 直到处理完最后一条评论,换行空两行输入问候语和署名 + +注意,信件回复请尽量使用英文。 + +迭代补丁 +-------- + +建议您每回复一条评论,就修改一处翻译。然后重新生成补丁,相信您现在已经具 +备了灵活使用 git am --amend 的能力。 + +每次迭代一个补丁,不要一次多个:: + + git am <您要修改的补丁> + # 直接对文件进行您的修改 + git add . + git commit --amend + +当您将所有的评论落实到位后,导出第二版补丁,并修改封面:: + + git format-patch -N -v 2 --cover-letter --thread=shallow + +打开 0 号补丁,在 BLURB HERE 处编写相较于上个版本,您做了哪些改动。 + +然后执行:: + + git send-email v2* --to <maintainer email addr> --cc <others addr> + +这样,新的一版补丁就又发送到邮件列表等待审阅,之后就是重复这个过程。 + +审阅周期 +-------- + +因为有时邮件列表比较繁忙,您的邮件可能会被淹没,如果超过两周没有得到任何 +回复,请自己回复自己,回复的内容为 Ping. + +最终,如果您落实好了所有的评论,并且一段时间后没有最新的评论,您的补丁将 +会先进入 Alex 的开发树,然后进入 linux-doc 开发树,最终在下个窗口打开 +时合并进 mainline 仓库。 + +紧急处理 +-------- + +如果您发送到邮件列表之后。发现发错了补丁集,尤其是在多个版本迭代的过程中; +自己发现了一些不妥的翻译;发送错了邮件列表…… + +git email 默认会抄送给您一份,所以您可以切换为审阅者的角色审查自己的补丁, +并留下评论,描述有何不妥,将在下个版本怎么改,并付诸行动,重新提交,但是 +注意频率,每天提交的次数不要超过两次。 + +新手任务 +-------- +对于首次参与 Linux 内核中文文档翻译的新手,建议您在 linux 目录中运行以下命令: +:: + + ./script/checktransupdate.py -l zh_CN`` + +该命令会列出需要翻译或更新的英文文档,结果同时保存在 checktransupdate.log 中。 + +关于详细操作说明,请参考:Documentation/translations/zh_CN/doc-guide/checktransupdate.rst。 + +进阶 +---- + +希望您不只是单纯的翻译内核文档,在熟悉了一起与社区工作之后,您可以审阅其他 +开发者的翻译,或者提出具有建设性的主张。与此同时,与文档对应的代码更加有趣, +而且需要完善的地方还有很多,勇敢地去探索,然后提交你的想法吧。 + +常见的问题 +========== + +Maintainer 回复补丁不能正常 apply +--------------------------------- + +这通常是因为您的补丁与邮件列表其他人的补丁产生了冲突,别人的补丁先被 apply 了, +您的补丁集就无法成功 apply 了,这需要您更新本地分支,在本地解决完冲突后再次提交。 + +请尽量避免冲突,不要多个人同时翻译一个目录。翻译之前可以通过 git log 查看您感 +兴趣的目录近期有没有其他人翻译,如果有,请提前私信联系对方,请求其代为发送您 +的补丁。如果对方未来一个月内没有提交新补丁的打算,您可以独自发送。 + +回信被邮件列表拒收 +------------------ + +大部分情况下,是由于您发送了非纯文本格式的信件,请尽量避免使用 webmail,推荐 +使用邮件客户端,比如 thunderbird,记得在设置中的回信配置那改为纯文本发送。 + +如果超过了 24 小时,您依旧没有在<https://lore.kernel.org/linux-doc/>发现您的 +邮件,请联系您的网络管理员帮忙解决。 diff --git a/Documentation/translations/zh_CN/index.rst b/Documentation/translations/zh_CN/index.rst index cc512ca54172..b08c09d8e96e 100644 --- a/Documentation/translations/zh_CN/index.rst +++ b/Documentation/translations/zh_CN/index.rst @@ -21,18 +21,18 @@ 这是中文内核文档树的顶级目录。内核文档,就像内核本身一样,在很大程度上是一 项正在进行的工作;当我们努力将许多分散的文件整合成一个连贯的整体时尤其如此。 另外,随时欢迎您对内核文档进行改进;如果您想提供帮助,请加入vger.kernel.org -上的linux-doc邮件列表。 - -顺便说下,中文文档也需要遵守内核编码风格,风格中中文和英文的主要不同就是中文 -的字符标点占用两个英文字符宽度,所以,当英文要求不要超过每行100个字符时, -中文就不要超过50个字符。另外,也要注意'-','='等符号与相关标题的对齐。在将 -补丁提交到社区之前,一定要进行必要的 ``checkpatch.pl`` 检查和编译测试,确保 -在 ``make htmldocs/pdfdocs`` 中不增加新的告警,最后,安装检查你生成的 -html/pdf 文件,确认它们看起来是正常的。 - -提交之前请确认你的补丁可以正常提交到中文文档维护库: -https://git.kernel.org/pub/scm/linux/kernel/git/alexs/linux.git/ -如果你的补丁依赖于其他人的补丁, 可以与其他人商量后由某一个人合并提交。 +上的linux-doc邮件列表,并按照Documentation/translations/zh_CN/how-to.rst的 +指引提交补丁。提交补丁之前请确保执行"make htmldocs”后无与翻译有关的异常输出。 + +如何翻译内核文档 +---------------- + +翻译文档本身是一件很简单的事情,但是提交补丁需要注意一些细节,为了保证内核中文文档的高质量可持续发展,提供了一份翻译指南。 + +.. toctree:: + :maxdepth: 1 + + how-to.rst 与Linux 内核社区一起工作 ------------------------ diff --git a/Documentation/translations/zh_CN/networking/alias.rst b/Documentation/translations/zh_CN/networking/alias.rst new file mode 100644 index 000000000000..e024d9eac50e --- /dev/null +++ b/Documentation/translations/zh_CN/networking/alias.rst @@ -0,0 +1,56 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/networking/alias.rst + +:翻译: + + 邱禹潭 Qiu Yutan <qiu.yutan@zte.com.cn> + +:校译: + +====== +IP别名 +====== + +IP别名是管理每个接口存在多个IP地址/子网掩码的一种过时方法。 +虽然更新的工具如iproute2支持每个接口多个地址/前缀, +但为了向后兼容性,别名仍被支持。 + +别名通过在使用 ifconfig 时在接口名后添加冒号和一个字符串来创建。 +这个字符串通常是数字,但并非必须。 + + +别名创建 +======== + +别名的创建是通过“特殊的”接口命名机制完成的:例如, +要为eth0创建一个 200.1.1.1 的别名... +:: + + # ifconfig eth0:0 200.1.1.1 等等 + ~~ -> 请求为eth0创建别名#0(如果尚不存在) + +该命令也会设置相应的路由表项。请注意:路由表项始终指向基础接口。 + + +别名删除 +======== + +通过关闭别名即可将其删除:: + + # ifconfig eth0:0 down + ~~~~~~~~~~ -> 将删除别名 + + +别名(重新)配置 +================ + +别名不是真实的设备,但程序应该能够正常配置和引用它们(ifconfig、route等)。 + + +与主设备的关系 +============== + +如果基础设备被关闭,则其上添加的所有别名也将被删除。 diff --git a/Documentation/translations/zh_CN/networking/index.rst b/Documentation/translations/zh_CN/networking/index.rst new file mode 100644 index 000000000000..bb0edcffd144 --- /dev/null +++ b/Documentation/translations/zh_CN/networking/index.rst @@ -0,0 +1,160 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/networking/index.rst + +:翻译: + + 王亚鑫 Wang Yaxin <wang.yaxin@zte.com.cn> + +:校译: + +网络 +==== + +有关网络设备(netdev)开发过程的详细指南,请参考::ref:`netdev-FAQ` + +目录: + +.. toctree:: + :maxdepth: 1 + + msg_zerocopy + napi + vxlan + netif-msg + xfrm_proc + netmem + alias + +Todolist: + +* af_xdp +* bareudp +* batman-adv +* can +* can_ucan_protocol +* device_drivers/index +* diagnostic/index +* dsa/index +* devlink/index +* caif/index +* ethtool-netlink +* ieee802154 +* iso15765-2 +* j1939 +* kapi +* failover +* net_dim +* net_failover +* page_pool +* phy +* sfp-phylink +* bridge +* snmp_counter +* checksum-offloads +* segmentation-offloads +* scaling +* tls +* tls-offload +* tls-handshake +* nfc +* 6lowpan +* 6pack +* arcnet-hardware +* arcnet +* atm +* ax25 +* bonding +* cdc_mbim +* dccp +* dctcp +* devmem +* dns_resolver +* driver +* eql +* fib_trie +* filter +* generic-hdlc +* generic_netlink +* netlink_spec/index +* gen_stats +* gtp +* ila +* ioam6-sysctl +* ip_dynaddr +* ipsec +* ip-sysctl +* ipv6 +* ipvlan +* ipvs-sysctl +* kcm +* l2tp +* lapb-module +* mac80211-injection +* mctp +* mpls-sysctl +* mptcp +* mptcp-sysctl +* multiqueue +* multi-pf-netdev +* net_cachelines/index +* netconsole +* netdev-features +* netdevices +* netfilter-sysctl +* nexthop-group-resilient +* nf_conntrack-sysctl +* nf_flowtable +* oa-tc6-framework +* openvswitch +* operstates +* packet_mmap +* phonet +* phy-link-topology +* pktgen +* plip +* ppp_generic +* proc_net_tcp +* pse-pd/index +* radiotap-headers +* rds +* regulatory +* representors +* rxrpc +* sctp +* secid +* seg6-sysctl +* skbuff +* smc-sysctl +* sriov +* statistics +* strparser +* switchdev +* sysfs-tagging +* tc-actions-env-rules +* tc-queue-filters +* tcp_ao +* tcp-thin +* team +* timestamping +* tipc +* tproxy +* tuntap +* udplite +* vrf +* x25 +* x25-iface +* xfrm_device +* xfrm_sync +* xfrm_sysctl +* xdp-rx-metadata +* xsk-tx-metadata + +.. only:: subproject and html + + Indices + ======= + + * :ref:`genindex` diff --git a/Documentation/translations/zh_CN/networking/msg_zerocopy.rst b/Documentation/translations/zh_CN/networking/msg_zerocopy.rst new file mode 100644 index 000000000000..821b32c4d1bf --- /dev/null +++ b/Documentation/translations/zh_CN/networking/msg_zerocopy.rst @@ -0,0 +1,223 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/networking/msg_zerocopy.rst + +:翻译: + + 王亚鑫 Wang Yaxin <wang.yaxin@zte.com.cn> + +:校译: + + - 徐鑫 xu xin <xu.xin16@zte.com.cn> + - 何配林 He Peilin <he.peilin@zte.com.cn> + +============ +MSG_ZEROCOPY +============ + +简介 +==== + +MSG_ZEROCOPY 标志用于启用套接字发送调用的免拷贝功能。该功能目前适用于 TCP、UDP 和 VSOCK +(使用 virtio 传输)套接字。 + +机遇与注意事项 +-------------- + +在用户进程与内核之间拷贝大型缓冲区可能会消耗大量资源。Linux 支持多种免拷贝的接口,如sendfile +和 splice。MSG_ZEROCOPY 标志将底层的拷贝避免机制扩展到了常见的套接字发送调用中。 + +免拷贝并非毫无代价。在实现上,它通过页面固定(page pinning)将按字节拷贝的成本替换为页面统计 +(page accounting)和完成通知的开销。因此,MSG_ZEROCOPY 通常仅在写入量超过大约 10 KB 时 +才有效。 + +页面固定还会改变系统调用的语义。它会暂时在进程和网络堆栈之间共享缓冲区。与拷贝不同,进程在系统 +调用返回后不能立即覆盖缓冲区,否则可能会修改正在传输中的数据。内核的完整性不会受到影响,但有缺 +陷的程序可能会破坏自己的数据流。 + +当内核返回数据可以安全修改的通知时,进程才可以修改数据。因此,将现有应用程序转换为使用 +MSG_ZEROCOPY 并非总是像简单地传递该标志那样容易。 + +更多信息 +-------- + +本文档的大部分内容是来自于 netdev 2.1 上发表的一篇长篇论文。如需更深入的信息,请参阅该论文和 +演讲,或者浏览 LWN.net 上的精彩报道,也可以直接阅读源码。 + + 论文、幻灯片、视频: + https://netdevconf.org/2.1/session.html?debruijn + + LWN 文章: + https://lwn.net/Articles/726917/ + + 补丁集: + [PATCH net-next v4 0/9] socket sendmsg MSG_ZEROCOPY + https://lore.kernel.org/netdev/20170803202945.70750-1-willemdebruijn.kernel@gmail.com + +接口 +==== + +传递 MSG_ZEROCOPY 标志是启用免拷贝功能的最明显步骤,但并非唯一的步骤。 + +套接字设置 +---------- + +当应用程序向 send 系统调用传递未定义的标志时,内核通常会宽容对待。默认情况下,它会简单地忽略 +这些标志。为了避免为那些偶然传递此标志的遗留进程启用免拷贝模式,进程必须首先通过设置套接字选项 +来表明意图: + +:: + + if (setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, &one, sizeof(one))) + error(1, errno, "setsockopt zerocopy"); + +传输 +---- + +对 send(或 sendto、sendmsg、sendmmsg)本身的改动非常简单。只需传递新的标志即可。 + +:: + + ret = send(fd, buf, sizeof(buf), MSG_ZEROCOPY); + +如果零拷贝操作失败,将返回 -1,并设置 errno 为 ENOBUFS。这种情况可能发生在套接字超出其 +optmem 限制,或者用户超出其锁定页面的 ulimit 时。 + +混合使用免拷贝和拷贝 +~~~~~~~~~~~~~~~~~~~~ + +许多工作负载同时包含大型和小型缓冲区。由于对于小数据包来说,免拷贝的成本高于拷贝,因此该 +功能是通过标志实现的。带有标志的调用和没有标志的调用可以安全地混合使用。 + +通知 +---- + +当内核认为可以安全地重用之前传递的缓冲区时,它必须通知进程。完成通知在套接字的错误队列上 +排队,类似于传输时间戳接口。 + +通知本身是一个简单的标量值。每个套接字都维护一个内部的无符号 32 位计数器。每次带有 +MSG_ZEROCOPY 标志的 send 调用成功发送数据时,计数器都会增加。如果调用失败或长度为零, +则计数器不会增加。该计数器统计系统调用的调用次数,而不是字节数。在 UINT_MAX 次调用后, +计数器会循环。 + +通知接收 +~~~~~~~~ + +下面的代码片段展示了 API 的使用。在最简单的情况下,每次 send 系统调用后,都会对错误队列 +进行轮询和 recvmsg 调用。 + +从错误队列读取始终是一个非阻塞操作。poll 调用用于阻塞,直到出现错误。它会在其输出标志中 +设置 POLLERR。该标志不需要在 events 字段中设置。错误会无条件地发出信号。 + +:: + + pfd.fd = fd; + pfd.events = 0; + if (poll(&pfd, 1, -1) != 1 || pfd.revents & POLLERR == 0) + error(1, errno, "poll"); + + ret = recvmsg(fd, &msg, MSG_ERRQUEUE); + if (ret == -1) + error(1, errno, "recvmsg"); + +read_notification(msg); + + +这个示例仅用于演示目的。在实际应用中,不等待通知,而是每隔几次 send 调用就进行一次非阻塞 +读取会更高效。 + +零拷贝通知可以与其他套接字操作乱序处理。通常,拥有错误队列套接字会阻塞其他操作,直到错误 +被读取。然而,零拷贝通知具有零错误代码,因此不会阻塞 send 和 recv 调用。 + +通知批处理 +~~~~~~~~~~~~ + +可以使用 recvmmsg 调用来一次性读取多个未决的数据包。这通常不是必需的。在每条消息中,内核 +返回的不是一个单一的值,而是一个范围。当错误队列上有一个通知正在等待接收时,它会将连续的通 +知合并起来。 + +当一个新的通知即将被排队时,它会检查队列尾部的通知的范围是否可以扩展以包含新的值。如果是这 +样,它会丢弃新的通知数据包,并增大未处理通知的范围上限值。 + +对于按顺序确认数据的协议(如 TCP),每个通知都可以合并到前一个通知中,因此在任何时候在等待 +的通知都不会超过一个。 + +有序交付是常见的情况,但不能保证。在重传和套接字拆除时,通知可能会乱序到达。 + +通知解析 +~~~~~~~~ + +下面的代码片段演示了如何解析控制消息:前面代码片段中的 read_notification() 调用。通知 +以标准错误格式 sock_extended_err 编码。 + +控制数据中的级别和类型字段是协议族特定的,对于 TCP 或 UDP 套接字,分别为 IP_RECVERR 或 +IPV6_RECVERR。对于 VSOCK 套接字,cmsg_level 为 SOL_VSOCK,cmsg_type 为 VSOCK_RECVERR。 + +错误来源是新的类型 SO_EE_ORIGIN_ZEROCOPY。如前所述,ee_errno 为零,以避免在套接字上 +阻塞地读取和写入系统调用。 + +32 位通知范围编码为 [ee_info, ee_data]。这个范围是包含边界值的。除了下面讨论的 ee_code +字段外,结构中的其他字段应被视为未定义的。 + +:: + + struct sock_extended_err *serr; + struct cmsghdr *cm; + + cm = CMSG_FIRSTHDR(msg); + if (cm->cmsg_level != SOL_IP && + cm->cmsg_type != IP_RECVERR) + error(1, 0, "cmsg"); + + serr = (void *) CMSG_DATA(cm); + if (serr->ee_errno != 0 || + serr->ee_origin != SO_EE_ORIGIN_ZEROCOPY) + error(1, 0, "serr"); + +printf("completed: %u..%u\n", serr->ee_info, serr->ee_data); + + +延迟拷贝 +~~~~~~~~ + +传递标志 MSG_ZEROCOPY 是向内核发出的一个提示,让内核采用免拷贝的策略,同时也是一种约 +定,即内核会对完成通知进行排队处理。但这并不保证拷贝操作一定会被省略。 + +拷贝避免不总是适用的。不支持分散/聚集 I/O 的设备无法发送由内核生成的协议头加上零拷贝用户 +数据组成的数据包。数据包可能需要在协议栈底层转换为一份私有数据副本,例如用于计算校验和。 + +在所有这些情况下,当内核释放对共享页面的持有权时,它会返回一个完成通知。该通知可能在(已 +拷贝)数据完全传输之前到达。因此。零拷贝完成通知并不是传输完成通知。 + +如果数据不在缓存中,延迟拷贝可能会比立即在系统调用中拷贝开销更大。进程还会因通知处理而产 +生成本,但却没有带来任何好处。因此,内核会在返回时通过在 ee_code 字段中设置标志 +SO_EE_CODE_ZEROCOPY_COPIED 来指示数据是否以拷贝的方式完成。进程可以利用这个信号,在 +同一套接字上后续的请求中停止传递 MSG_ZEROCOPY 标志。 + +实现 +==== + +环回 +---- + +对于 TCP 和 UDP: +如果接收进程不读取其套接字,发送到本地套接字的数据可能会无限期排队。无限期的通知延迟是不 +可接受的。因此,所有使用 MSG_ZEROCOPY 生成并环回到本地套接字的数据包都将产生延迟拷贝。 +这包括环回到数据包套接字(例如,tcpdump)和 tun 设备。 + +对于 VSOCK: +发送到本地套接字的数据路径与非本地套接字相同。 + +测试 +==== + +更具体的示例代码可以在内核源码的 tools/testing/selftests/net/msg_zerocopy.c 中找到。 + +要留意环回约束问题。该测试可以在一对主机之间进行。但如果是在本地的一对进程之间运行,例如当使用 +msg_zerocopy.sh 脚本在跨命名空间的虚拟以太网(veth)对之间运行时,测试将不会显示出任何性能 +提升。为了便于测试,可以通过让 skb_orphan_frags_rx 与 skb_orphan_frags 相同,来暂时放宽 +环回限制。 + +对于 VSOCK 类型套接字的示例可以在 tools/testing/vsock/vsock_test_zerocopy.c 中找到。 diff --git a/Documentation/translations/zh_CN/networking/napi.rst b/Documentation/translations/zh_CN/networking/napi.rst new file mode 100644 index 000000000000..619971c3dea3 --- /dev/null +++ b/Documentation/translations/zh_CN/networking/napi.rst @@ -0,0 +1,362 @@ +.. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/networking/napi.rst + +:翻译: + + 王亚鑫 Yaxin Wang <wang.yaxin@zte.com.cn> + +==== +NAPI +==== + +NAPI 是 Linux 网络堆栈中使用的事件处理机制。NAPI 的名称现在不再代表任何特定含义 [#]_。 + +在基本操作中,设备通过中断通知主机有新事件发生。主机随后调度 NAPI 实例来处理这些事件。 +该设备也可以通过 NAPI 进行事件轮询,而无需先接收中断信号(:ref:`忙轮询<poll_zh_CN>`)。 + +NAPI 处理通常发生在软中断上下文中,但有一个选项,可以使用 :ref:`单独的内核线程<threaded_zh_CN>` +来进行 NAPI 处理。 + +总的来说,NAPI 为驱动程序抽象了事件(数据包接收和发送)处理的上下文环境和配置情况。 + +驱动程序API +=========== + +NAPI 最重要的两个元素是 struct napi_struct 和关联的 poll 方法。struct napi_struct +持有 NAPI 实例的状态,而方法则是与驱动程序相关的事件处理器。该方法通常会释放已传输的发送 +(Tx)数据包并处理新接收的数据包。 + +.. _drv_ctrl_zh_CN: + +控制API +------- + +netif_napi_add() 和 netif_napi_del() 用于向系统中添加/删除一个 NAPI 实例。实例会被 +附加到作为参数传递的 netdevice上(并在 netdevice 注销时自动删除)。实例在添加时处于禁 +用状态。 + +napi_enable() 和 napi_disable() 管理禁用状态。禁用的 NAPI 不会被调度,并且保证其 +poll 方法不会被调用。napi_disable() 会等待 NAPI 实例的所有权被释放。 + +这些控制 API 并非幂等的。控制 API 调用在面对数据路径 API 的并发使用时是安全的,但控制 +API 调用顺序错误可能会导致系统崩溃、死锁或竞态条件。例如,连续多次调用 napi_disable() +会造成死锁。 + +数据路径API +----------- + +napi_schedule() 是调度 NAPI 轮询的基本方法。驱动程序应在其中断处理程序中调用此函数 +(更多信息请参见 :ref:`drv_sched_zh_CN`)。成功的 napi_schedule() 调用将获得 NAPI 实例 +的所有权。 + +之后,在 NAPI 被调度后,驱动程序的 poll 方法将被调用以处理事件/数据包。该方法接受一个 +``budget`` 参数 - 驱动程序可以处理任意数量的发送 (Tx) 数据包完成,但处理最多处理 +``budget`` 个接收 (Rx) 数据包。处理接收数据包通常开销更大。 + +换句话说,对于接收数据包的处理,``budget`` 参数限制了驱动程序在单次轮询中能够处理的数 +据包数量。当 ``budget`` 为 0 时,像页面池或 XDP 这类专门用于接收的 API 根本无法使用。 +无论 ``budget`` 的值是多少,skb 的发送处理都应该进行,但是如果 ``budget`` 参数为 0, +驱动程序就不能调用任何 XDP(或页面池)API。 + +.. warning:: + + 如果内核仅尝试处理skb的发送完成情况,而不处理接收 (Rx) 或 XDP 数据包,那么 ``budget`` + 参数可能为 0。 + +轮询方法会返回已完成的工作量。如果驱动程序仍有未完成的工作(例如,``budget`` 已用完), +轮询方法应精确返回 ``budget`` 的值。在这种情况下,NAPI 实例将再次被处理 / 轮询(无需 +重新调度)。 + +如果事件处理已完成(所有未处理的数据包都已处理完毕),轮询方法在返回之前应调用 napi_complete_done()。 +napi_complete_done() 会释放实例的所有权。 + +.. warning:: + + 当出现既完成了所有事件处理,又恰好达到了 ``budget`` 数量的情况时,必须谨慎处理。因为没 + 有办法将这种(很少出现的)情况报告给协议栈,所以驱动程序要么不调用 napi_complete_done() + 并等待再次被调用,要么返回 ``budget - 1``。 + + 当 ``budget`` 为 0 时,napi_complete_done() 绝对不能被调用。 + +调用序列 +-------- + +驱动程序不应假定调用的顺序是固定不变的。即使驱动程序没有调度该实例,轮询方法也可能会被调用 +(除非该实例处于禁用状态)。同样,即便 napi_schedule() 调用成功,也不能保证轮询方法一定 +会被调用(例如,如果该实例被禁用)。 + +正如在 :ref:`drv_ctrl_zh_CN` 部分所提到的,napi_disable() 以及后续对轮询方法的调用, +仅会等待该实例的所有权被释放,而不会等待轮询方法退出。这意味着,驱动程序在调用 napi_complete_done() +之后,应避免访问任何数据结构。 + +.. _drv_sched_zh_CN: + +调度与IRQ屏蔽 +------------- + +驱动程序应在调度 NAPI 实例后保持中断屏蔽 - 直到 NAPI 轮询完成,任何进一步的中断都是不必要的。 + +显式屏蔽中断的驱动程序(而非设备自动屏蔽 IRQ)应使用 napi_schedule_prep() 和 +__napi_schedule() 调用: + +.. code-block:: c + + if (napi_schedule_prep(&v->napi)) { + mydrv_mask_rxtx_irq(v->idx); + /* 在屏蔽后调度以避免竞争 */ + __napi_schedule(&v->napi); + } + +IRQ 仅应在成功调用 napi_complete_done() 后取消屏蔽: + +.. code-block:: c + + if (budget && napi_complete_done(&v->napi, work_done)) { + mydrv_unmask_rxtx_irq(v->idx); + return min(work_done, budget - 1); + } + +napi_schedule_irqoff() 是 napi_schedule() 的一个变体,它利用了在中断请求(IRQ)上下文 +环境中调用所带来的特性(无需屏蔽中断)。如果中断请求(IRQ)是通过线程处理的(例如启用了 +``PREEMPT_RT`` 时的情况),napi_schedule_irqoff() 会回退为使用 napi_schedule() 。 + +实例到队列的映射 +---------------- + +现代设备每个接口有多个 NAPI 实例(struct napi_struct)。关于实例如何映射到队列和中断没有 +严格要求。NAPI 主要是事件处理/轮询抽象,没有用户可见的语义。也就是说,大多数网络设备最终以 +非常相似的方式使用 NAPI。 + +NAPI 实例最常以 1:1:1 映射到中断和队列对(队列对是由一个接收队列和一个发送队列组成的一组 +队列)。 + +在不太常见的情况下,一个 NAPI 实例可能会用于处理多个队列,或者在单个内核上,接收(Rx)队列 +和发送(Tx)队列可以由不同的 NAPI 实例来处理。不过,无论队列如何分配,通常 NAPI 实例和中断 +之间仍然保持一一对应的关系。 + +值得注意的是,ethtool API 使用了 “通道” 这一术语,每个通道可以是 ``rx`` (接收)、``tx`` +(发送)或 ``combined`` (组合)类型。目前尚不清楚一个通道具体由什么构成,建议的理解方式是 +将一个通道视为一个为特定类型队列提供服务的 IRQ(中断请求)/ NAPI 实例。例如,配置为 1 个 +``rx`` 通道、1 个 ``tx`` 通道和 1 个 ``combined`` 通道的情况下,预计会使用 3 个中断、 +2 个接收队列和 2 个发送队列。 + +持久化NAPI配置 +-------------- + +驱动程序常常会动态地分配和释放 NAPI 实例。这就导致每当 NAPI 实例被重新分配时,与 NAPI 相关 +的用户配置就会丢失。netif_napi_add_config() API接口通过将每个 NAPI 实例与基于驱动程序定义 +的索引值(如队列编号)的持久化 NAPI 配置相关联,从而避免了这种配置丢失的情况。 + +使用此 API 可实现持久化的 NAPI 标识符(以及其他设置),这对于使用 ``SO_INCOMING_NAPI_ID`` +的用户空间程序来说是有益的。有关其他 NAPI 配置的设置,请参阅以下章节。 + +驱动程序应尽可能尝试使用 netif_napi_add_config()。 + +用户API +======= + +用户与 NAPI 的交互依赖于 NAPI 实例 ID。这些实例 ID 仅通过 ``SO_INCOMING_NAPI_ID`` 套接字 +选项对用户可见。 + +用户可以使用 Netlink 来查询某个设备或设备队列的 NAPI 标识符。这既可以在用户应用程序中通过编程 +方式实现,也可以使用内核源代码树中包含的一个脚本:tools/net/ynl/pyynl/cli.py 来完成。 + +例如,使用该脚本转储某个设备的所有队列(这将显示每个队列的 NAPI 标识符): + + +.. code-block:: bash + + $ kernel-source/tools/net/ynl/pyynl/cli.py \ + --spec Documentation/netlink/specs/netdev.yaml \ + --dump queue-get \ + --json='{"ifindex": 2}' + +有关可用操作和属性的更多详细信息,请参阅 ``Documentation/netlink/specs/netdev.yaml``。 + +软件IRQ合并 +----------- + +默认情况下,NAPI 不执行任何显式的事件合并。在大多数场景中,数据包的批量处理得益于设备进行 +的中断请求(IRQ)合并。不过,在某些情况下,软件层面的合并操作也很有帮助。 + +可以将 NAPI 配置为设置一个重新轮询定时器,而不是在处理完所有数据包后立即取消屏蔽硬件中断。 +网络设备的 ``gro_flush_timeout`` sysfs 配置项可用于控制该定时器的延迟时间,而 ``napi_defer_hard_irqs`` +则用于控制在 NAPI 放弃并重新启用硬件中断之前,连续进行空轮询的次数。 + +上述参数也可以通过 Netlink 的 netdev-genl 接口,基于每个 NAPI 实例进行设置。当通过 +Netlink 进行配置且是基于每个 NAPI 实例设置时,上述参数使用连字符(-)而非下划线(_) +来命名,即 ``gro-flush-timeout`` 和 ``napi-defer-hard-irqs``。 + +基于每个 NAPI 实例的配置既可以在用户应用程序中通过编程方式完成,也可以使用内核源代码树中的 +一个脚本实现,该脚本为 ``tools/net/ynl/pyynl/cli.py``。 + +例如,通过如下方式使用该脚本: + +.. code-block:: bash + + $ kernel-source/tools/net/ynl/pyynl/cli.py \ + --spec Documentation/netlink/specs/netdev.yaml \ + --do napi-set \ + --json='{"id": 345, + "defer-hard-irqs": 111, + "gro-flush-timeout": 11111}' + +类似地,参数 ``irq-suspend-timeout`` 也可以通过 netlink 的 netdev-genl 设置。没有全局 +的 sysfs 参数可用于设置这个值。 + +``irq-suspend-timeout`` 用于确定应用程序可以完全挂起 IRQ 的时长。与 SO_PREFER_BUSY_POLL +结合使用,后者可以通过 ``EPIOCSPARAMS`` ioctl 在每个 epoll 上下文中设置。 + +.. _poll_zh_CN: + +忙轮询 +------ + +忙轮询允许用户进程在设备中断触发前检查传入的数据包。与其他忙轮询一样,它以 CPU 周期换取更低 +的延迟(生产环境中 NAPI 忙轮询的使用尚不明确)。 + +通过在选定套接字上设置 ``SO_BUSY_POLL`` 或使用全局 ``net.core.busy_poll`` 和 ``net.core.busy_read`` +等 sysctls 启用忙轮询。还存在基于 io_uring 的 NAPI 忙轮询 API 可使用。 + +基于epoll的忙轮询 +----------------- + +可以从 ``epoll_wait`` 调用直接触发数据包处理。为了使用此功能,用户应用程序必须确保添加到 +epoll 上下文的所有文件描述符具有相同的 NAPI ID。 + +如果应用程序使用专用的 acceptor 线程,那么该应用程序可以获取传入连接的 NAPI ID(使用 +SO_INCOMING_NAPI_ID)然后将该文件描述符分发给工作线程。工作线程将该文件描述符添加到其 +epoll 上下文。这确保了每个工作线程的 epoll 上下文中所包含的文件描述符具有相同的 NAPI ID。 + +或者,如果应用程序使用 SO_REUSEPORT,可以插入 bpf 或 ebpf 程序来分发传入连接,使得每个 +线程只接收具有相同 NAPI ID 的连接。但是必须谨慎处理系统中可能存在多个网卡的情况。 + +为了启用忙轮询,有两种选择: + +1. ``/proc/sys/net/core/busy_poll`` 可以设置为微秒数以在忙循环中等待事件。这是一个系统 + 范围的设置,将导致所有基于 epoll 的应用程序在调用 epoll_wait 时忙轮询。这可能不是理想 + 的情况,因为许多应用程序可能不需要忙轮询。 + +2. 使用最新内核的应用程序可以在 epoll 上下文的文件描述符上发出 ioctl 来设置(``EPIOCSPARAMS``) + 或获取(``EPIOCGPARAMS``) ``struct epoll_params``,用户程序定义如下: + +.. code-block:: c + + struct epoll_params { + uint32_t busy_poll_usecs; + uint16_t busy_poll_budget; + uint8_t prefer_busy_poll; + + /* 将结构填充到 64 位的倍数 */ + uint8_t __pad; + }; + +IRQ缓解 +------- + +虽然忙轮询旨在用于低延迟应用,但类似的机制可用于减少中断请求。 + +每秒高请求的应用程序(尤其是路由/转发应用程序和特别使用 AF_XDP 套接字的应用程序) +可能希望在处理完一个请求或一批数据包之前不被中断。 + +此类应用程序可以向内核承诺会定期执行忙轮询操作,而驱动程序应将设备的中断请求永久屏蔽。 +通过使用 ``SO_PREFER_BUSY_POLL`` 套接字选项可启用此模式。为避免系统出现异常,如果 +在 ``gro_flush_timeout`` 时间内没有进行任何忙轮询调用,该承诺将被撤销。对于基于 +epoll 的忙轮询应用程序,可以将 ``struct epoll_params`` 结构体中的 ``prefer_busy_poll`` +字段设置为 1,并使用 ``EPIOCSPARAMS`` 输入 / 输出控制(ioctl)操作来启用此模式。 +更多详情请参阅上述章节。 + +NAPI 忙轮询的 budget 低于默认值(这符合正常忙轮询的低延迟意图)。减少中断请求的场景中 +并非如此,因此 budget 可以通过 ``SO_BUSY_POLL_BUDGET`` 套接字选项进行调整。对于基于 +epoll 的忙轮询应用程序,可以通过调整 ``struct epoll_params`` 中的 ``busy_poll_budget`` +字段为特定值,并使用 ``EPIOCSPARAMS`` ioctl 在特定 epoll 上下文中设置。更多详细信 +息请参见上述部分。 + +需要注意的是,为 ``gro_flush_timeout`` 选择较大的值会延迟中断请求,以实现更好的批 +量处理,但在系统未满载时会增加延迟。为 ``gro_flush_timeout`` 选择较小的值可能会因 +设备中断请求和软中断处理而干扰尝试进行忙轮询的用户应用程序。应权衡这些因素后谨慎选择 +该值。基于 epoll 的忙轮询应用程序可以通过为 ``maxevents`` 选择合适的值来减少用户 +处理的干扰。 + +用户可能需要考虑使用另一种方法,IRQ 挂起,以帮助应对这些权衡问题。 + +IRQ挂起 +------- + +IRQ 挂起是一种机制,其中设备 IRQ 在 epoll 触发 NAPI 数据包处理期间被屏蔽。 + +只要应用程序对 epoll_wait 的调用成功获取事件,内核就会推迟 IRQ 挂起定时器。如果 +在忙轮询期间没有获取任何事件(例如,因为网络流量减少),则会禁用IRQ挂起功能,并启 +用上述减少中断请求的策略。 + +这允许用户在 CPU 消耗和网络处理效率之间取得平衡。 + +要使用此机制: + + 1. 每个 NAPI 的配置参数 ``irq-suspend-timeout`` 应设置为应用程序可以挂起 + IRQ 的最大时间(纳秒)。这通过 netlink 完成,如上所述。此超时时间作为一 + 种安全机制,如果应用程序停滞,将重新启动中断驱动程序的中断处理。此值应选择 + 为覆盖用户应用程序调用 epoll_wait 处理数据所需的时间,需注意的是,应用程 + 序可通过在调用 epoll_wait 时设置 ``max_events`` 来控制获取的数据量。 + + 2. sysfs 参数或每个 NAPI 的配置参数 ``gro_flush_timeout`` 和 ``napi_defer_hard_irqs`` + 可以设置为较低值。它们将用于在忙轮询未找到数据时延迟 IRQs。 + + 3. 必须将 ``prefer_busy_poll`` 标志设置为 true。如前文所述,可使用 ``EPIOCSPARAMS`` + ioctl操作来完成此设置。 + + 4. 应用程序按照上述方式使用 epoll 触发 NAPI 数据包处理。 + +如上所述,只要后续对 epoll_wait 的调用向用户空间返回事件,``irq-suspend-timeout`` +就会被推迟并且 IRQ 会被禁用。这允许应用程序在无干扰的情况下处理数据。 + +一旦 epoll_wait 的调用没有找到任何事件,IRQ 挂起会被自动禁用,并且 ``gro_flush_timeout`` +和 ``napi_defer_hard_irqs`` 缓解机制将开始起作用。 + +预期是 ``irq-suspend-timeout`` 的设置值会远大于 ``gro_flush_timeout``,因为 ``irq-suspend-timeout`` +应在一个用户空间处理周期内暂停中断请求。 + +虽然严格来说不必通过 ``napi_defer_hard_irqs`` 和 ``gro_flush_timeout`` 来执行 IRQ 挂起, +但强烈建议这样做。 + +中断请求挂起会使系统在轮询模式和由中断驱动的数据包传输模式之间切换。在网络繁忙期间,``irq-suspend-timeout`` +会覆盖 ``gro_flush_timeout``,使系统保持忙轮询状态,但是当 epoll 未发现任何事件时,``gro_flush_timeout`` +和 ``napi_defer_hard_irqs`` 的设置将决定下一步的操作。 + +有三种可能的网络处理和数据包交付循环: + +1) 硬中断 -> 软中断 -> NAPI 轮询;基本中断交付 +2) 定时器 -> 软中断 -> NAPI 轮询;延迟的 IRQ 处理 +3) epoll -> 忙轮询 -> NAPI 轮询;忙循环 + +循环 2 可以接管循环 1,如果设置了 ``gro_flush_timeout`` 和 ``napi_defer_hard_irqs``。 + +如果设置了 ``gro_flush_timeout`` 和 ``napi_defer_hard_irqs``,循环 2 和 3 将互相“争夺”控制权。 + +在繁忙时期,``irq-suspend-timeout`` 用作循环 2 的定时器,这基本上使网络处理倾向于循环 3。 + +如果不设置 ``gro_flush_timeout`` 和 ``napi_defer_hard_irqs``,循环 3 无法从循环 1 接管。 + +因此,建议设置 ``gro_flush_timeout`` 和 ``napi_defer_hard_irqs``,因为若不这样做,设置 +``irq-suspend-timeout`` 可能不会有明显效果。 + +.. _threaded_zh_CN: + +线程化NAPI +---------- + +线程化 NAPI 是一种操作模式,它使用专用的内核线程而非软件中断上下文来进行 NAPI 处理。这种配置 +是针对每个网络设备的,并且会影响该设备的所有 NAPI 实例。每个 NAPI 实例将生成一个单独的线程 +(称为 ``napi/${ifc-name}-${napi-id}`` )。 + +建议将每个内核线程固定到单个 CPU 上,这个 CPU 与处理中断的 CPU 相同。请注意,中断请求(IRQ) +和 NAPI 实例之间的映射关系可能并不简单(并且取决于驱动程序)。NAPI 实例 ID 的分配顺序将与内 +核线程的进程 ID 顺序相反。 + +线程化 NAPI 是通过向网络设备的 sysfs 目录中的 ``threaded`` 文件写入 0 或 1 来控制的。 + +.. rubric:: 脚注 + +.. [#] NAPI 最初在 2.4 Linux 中被称为 New API。 diff --git a/Documentation/translations/zh_CN/networking/netif-msg.rst b/Documentation/translations/zh_CN/networking/netif-msg.rst new file mode 100644 index 000000000000..877399b169fe --- /dev/null +++ b/Documentation/translations/zh_CN/networking/netif-msg.rst @@ -0,0 +1,92 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/networking/netif-msg.rst + +:翻译: + + 王亚鑫 Wang Yaxin <wang.yaxin@zte.com.cn> + +================ +网络接口消息级别 +================ + +网络接口消息级别设置的设计方案。 + +历史背景 +-------- + +调试消息接口的设计遵循并受制于向后兼容性及历史实践。理解其发展历史有助于把握 +当前实践,并将其与旧版驱动代码相关联。 + +自Linux诞生之初,每个网络设备驱动均包含一个本地整型变量以控制调试消息级别。 +消息级别范围为0至7,数值越大表示输出越详细。 + +消息级别的定义在3级之后未明确细化,但实际实现通常与指定级别相差±1。驱动程序 +成熟后,冗余的详细级别消息常被移除。 + + - 0 最简消息,仅显示致命错误的关键信息。 + - 1 标准消息,初始化状态。无运行时消息。 + - 2 特殊介质选择消息,通常由定时器驱动。 + - 3 接口开启和停止消息,包括正常状态信息。 + - 4 Tx/Rx帧错误消息及异常驱动操作。 + - 5 Tx数据包队列信息、中断事件。 + - 6 每个完成的Tx数据包和接收的Rx数据包状态。 + - 7 Tx/Rx数据包初始内容。 + +最初,该消息级别变量在各驱动中具有唯一名称(如"lance_debug"),便于通过 +内核符号调试器定位和修改其设置。模块化内核出现后,变量统一重命名为"debug", +并作为模块参数设置。 + +这种方法效果良好。然而,人们始终对附加功能存在需求。多年来,以下功能逐渐 +成为合理且易于实现的增强方案: + + - 通过ioctl()调用修改消息级别。 + - 按接口而非驱动设置消息级别。 + - 对发出的消息类型进行更具选择性的控制。 + +netif_msg 建议添加了这些功能,仅带来了轻微的复杂性增加和代码规模增长。 + +推荐方案如下: + + - 保留驱动级整型变量"debug"作为模块参数,默认值为'1'。 + + - 添加一个名为 "msg_enable" 的接口私有变量。该变量是位图而非级别, + 并按如下方式初始化:: + + 1 << debug + + 或更精确地说:: + + debug < 0 ? 0 : 1 << min(sizeof(int)-1, debug) + + 消息应从以下形式更改:: + + if (debug > 1) + printk(MSG_DEBUG "%s: ... + + 改为:: + + if (np->msg_enable & NETIF_MSG_LINK) + printk(MSG_DEBUG "%s: ... + +消息级别命名对应关系 + + + ========= =================== ============ + 旧级别 名称 位位置 + ========= =================== ============ + 1 NETIF_MSG_PROBE 0x0002 + 2 NETIF_MSG_LINK 0x0004 + 2 NETIF_MSG_TIMER 0x0004 + 3 NETIF_MSG_IFDOWN 0x0008 + 3 NETIF_MSG_IFUP 0x0008 + 4 NETIF_MSG_RX_ERR 0x0010 + 4 NETIF_MSG_TX_ERR 0x0010 + 5 NETIF_MSG_TX_QUEUED 0x0020 + 5 NETIF_MSG_INTR 0x0020 + 6 NETIF_MSG_TX_DONE 0x0040 + 6 NETIF_MSG_RX_STATUS 0x0040 + 7 NETIF_MSG_PKTDATA 0x0080 + ========= =================== ============ diff --git a/Documentation/translations/zh_CN/networking/netmem.rst b/Documentation/translations/zh_CN/networking/netmem.rst new file mode 100644 index 000000000000..fe351a240f02 --- /dev/null +++ b/Documentation/translations/zh_CN/networking/netmem.rst @@ -0,0 +1,92 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/networking/netmem.rst + +:翻译: + + 王亚鑫 Wang Yaxin <wang.yaxin@zte.com.cn> + +================== +网络驱动支持Netmem +================== + +本文档概述了网络驱动支持netmem(一种抽象内存类型)的要求,该内存类型 +支持设备内存 TCP 等功能。通过支持netmem,驱动可以灵活适配不同底层内 +存类型(如设备内存TCP),且无需或仅需少量修改。 + +Netmem的优势: + +* 灵活性:netmem 可由不同内存类型(如 struct page、DMA-buf)支持, + 使驱动程序能够支持设备内存 TCP 等各种用例。 +* 前瞻性:支持netmem的驱动可无缝适配未来依赖此功能的新特性。 +* 简化开发:驱动通过统一API与netmem交互,无需关注底层内存的实现差异。 + +驱动RX要求 +========== + +1. 驱动必须支持page_pool。 + +2. 驱动必须支持tcp-data-split ethtool选项。 + +3. 驱动必须使用page_pool netmem API处理有效载荷内存。当前netmem API + 与page API一一对应。转换时需要将page API替换为netmem API,并用驱动 + 中的netmem_refs跟踪内存而非 `struct page *`: + + - page_pool_alloc -> page_pool_alloc_netmem + - page_pool_get_dma_addr -> page_pool_get_dma_addr_netmem + - page_pool_put_page -> page_pool_put_netmem + + 目前并非所有页 pageAPI 都有对应的 netmem 等效接口。如果你的驱动程序 + 依赖某个尚未实现的 netmem API,请直接实现并提交至 netdev@邮件列表, + 或联系维护者及 almasrymina@google.com 协助添加该 netmem API。 + +4. 驱动必须设置以下PP_FLAGS: + + - PP_FLAG_DMA_MAP:驱动程序无法对 netmem 执行 DMA 映射。此时驱动 + 程序必须将 DMA 映射操作委托给 page_pool,由其判断何时适合(或不适合) + 进行 DMA 映射。 + - PP_FLAG_DMA_SYNC_DEV:驱动程序无法保证 netmem 的 DMA 地址一定能 + 完成 DMA 同步。此时驱动程序必须将 DMA 同步操作委托给 page_pool,由 + 其判断何时适合(或不适合)进行 DMA 同步。 + - PP_FLAG_ALLOW_UNREADABLE_NETMEM:仅当启用 tcp-data-split 时, + 驱动程序必须显式设置此标志。 + +5. 驱动不得假设netmem可读或基于页。当netmem_address()返回NULL时,表示 +内存不可读。驱动需正确处理不可读的netmem,例如,当netmem_address()返回 +NULL时,避免访问内容。 + + 理想情况下,驱动程序不应通过netmem_is_net_iov()等辅助函数检查底层 + netmem 类型,也不应通过netmem_to_page()或netmem_to_net_iov()将 + netmem 转换为其底层类型。在大多数情况下,系统会提供抽象这些复杂性的 + netmem 或 page_pool 辅助函数(并可根据需要添加更多)。 + +6. 驱动程序必须使用page_pool_dma_sync_netmem_for_cpu()代替dma_sync_single_range_for_cpu()。 +对于某些内存提供者,CPU 的 DMA 同步将由 page_pool 完成;而对于其他提供者 +(特别是 dmabuf 内存提供者),CPU 的 DMA 同步由使用 dmabuf API 的用户空 +间负责。驱动程序必须将整个 DMA 同步操作委托给 page_pool,以确保操作正确执行。 + +7. 避免在 page_pool 之上实现特定于驱动程序内存回收机制。由于 netmem 可能 +不由struct page支持,驱动程序不能保留struct page来进行自定义回收。不过, +可为此目的通过page_pool_fragment_netmem()或page_pool_ref_netmem()保留 +page_pool 引用,但需注意某些 netmem 类型的循环时间可能更长(例如零拷贝场景 +下用户空间持有引用的情况)。 + +驱动TX要求 +========== + +1. 驱动程序绝对不能直接把 netmem 的 dma_addr 传递给任何 dma-mapping API。这 +是由于 netmem 的 dma_addr 可能源自 dma-buf 这类和 dma-mapping API 不兼容的 +源头。 + +应当使用netmem_dma_unmap_page_attrs()和netmem_dma_unmap_addr_set()等辅助 +函数来替代dma_unmap_page[_attrs]()、dma_unmap_addr_set()。不管 dma_addr +来源如何,netmem 的这些变体都能正确处理 netmem dma_addr,在合适的时候会委托给 +dma-mapping API 去处理。 + +目前,并非所有的 dma-mapping API 都有对应的 netmem 版本。要是你的驱动程序需要 +使用某个还不存在的 netmem API,你可以自行添加并提交到 netdev@,也可以联系维护 +人员或者发送邮件至 almasrymina@google.com 寻求帮助。 + +2. 驱动程序应通过设置 netdev->netmem_tx = true 来表明自身支持 netmem 功能。 diff --git a/Documentation/translations/zh_CN/networking/vxlan.rst b/Documentation/translations/zh_CN/networking/vxlan.rst new file mode 100644 index 000000000000..e319eddfcdbe --- /dev/null +++ b/Documentation/translations/zh_CN/networking/vxlan.rst @@ -0,0 +1,85 @@ +.. SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/networking/vxlan.rst + +:翻译: + + 范雨 Fan Yu <fan.yu9@zte.com.cn> + +:校译: + + - 邱禹潭 Qiu Yutan <qiu.yutan@zte.com.cn> + - 徐鑫 xu xin <xu.xin16@zte.com.cn> + +========================== +虚拟扩展本地局域网协议文档 +========================== + +VXLAN 协议是一种隧道协议,旨在解决 IEEE 802.1q 中 VLAN ID(4096)有限的问题。 +VXLAN 将标识符的大小扩展到 24 位(16777216)。 + +VXLAN 在 IETF RFC 7348 中进行了描述,并已由多家供应商设计实现。 +该协议通过 UDP 协议运行,并使用特定目的端口。 +本文档介绍了 Linux 内核隧道设备,Openvswitch 也有单独的 VXLAN 实现。 + +与大多数隧道不同,VXLAN 是 1 对 N 的网络,而不仅仅是点对点网络。 +VXLAN 设备可以通过类似于学习桥接器的方式动态学习另一端点的 IP 地址,也可以利用静态配置的转发条目。 + +VXLAN 的管理方式与它的两个近邻 GRE 和 VLAN 相似。 +配置 VXLAN 需要 iproute2 的版本与 VXLAN 首次向上游合并的内核版本相匹配。 + +1. 创建 vxlan 设备:: + + # ip link add vxlan0 type vxlan id 42 group 239.1.1.1 dev eth1 dstport 4789 + +这将创建一个名为 vxlan0 的网络设备,该设备通过 eth1 使用组播组 239.1.1.1 处理转发表中没有对应条目的流量。 +目标端口号设置为 IANA 分配的值 4789,VXLAN 的 Linux 实现早于 IANA 选择标准目的端口号的时间。 +因此默认使用 Linux 选择的值,以保持向后兼容性。 + +2. 删除 vxlan 设备:: + + # ip link delete vxlan0 + +3. 查看 vxlan 设备信息:: + + # ip -d link show vxlan0 + +使用新的 bridge 命令可以创建、销毁和显示 vxlan 转发表。 + +1. 创建vxlan转发表项:: + + # bridge fdb add to 00:17:42:8a:b4:05 dst 192.19.0.2 dev vxlan0 + +2. 删除vxlan转发表项:: + + # bridge fdb delete 00:17:42:8a:b4:05 dev vxlan0 + +3. 显示vxlan转发表项:: + + # bridge fdb show dev vxlan0 + +以下网络接口控制器特性可能表明对 UDP 隧道相关的卸载支持(最常见的是 VXLAN 功能, +但是对特定封装协议的支持取决于网络接口控制器): + + - `tx-udp_tnl-segmentation` + - `tx-udp_tnl-csum-segmentation` + 对 UDP 封装帧执行 TCP 分段卸载的能力 + + - `rx-udp_tunnel-port-offload` + 在接收端解析 UDP 封装帧,使网络接口控制器能够执行协议感知卸载, + 例如内部帧的校验和验证卸载(只有不带协议感知卸载的网络接口控制器才需要) + +对于支持 `rx-udp_tunnel-port-offload` 的设备,可使用 `ethtool` 查询当前卸载端口的列表:: + + $ ethtool --show-tunnels eth0 + Tunnel information for eth0: + UDP port table 0: + Size: 4 + Types: vxlan + No entries + UDP port table 1: + Size: 4 + Types: geneve, vxlan-gpe + Entries (1): + port 1230, vxlan-gpe diff --git a/Documentation/translations/zh_CN/networking/xfrm_proc.rst b/Documentation/translations/zh_CN/networking/xfrm_proc.rst new file mode 100644 index 000000000000..a2ae86c44707 --- /dev/null +++ b/Documentation/translations/zh_CN/networking/xfrm_proc.rst @@ -0,0 +1,126 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/networking/xfrm_proc.rst + +:翻译: + + 王亚鑫 Wang Yaxin <wang.yaxin@zte.com.cn> + +================================= +XFRM proc - /proc/net/xfrm_* 文件 +================================= + +作者:Masahide NAKAMURA <nakam@linux-ipv6.org> + + +转换统计信息 +------------ + +`xfrm_proc` 提供一组统计计数器,显示转换过程中丢弃的数据包及其原因。 +这些计数器属于Linux私有MIB的一部分,可通过 `/proc/net/xfrm_stat` +查看。 + +入站错误 +~~~~~~~~ + +XfrmInError: + 未匹配其他类别的所有错误 + +XfrmInBufferError: + 缓冲区不足 + +XfrmInHdrError: + 头部错误 + +XfrmInNoStates: + 未找到状态 + (入站SPI、地址或SA的IPsec协议不匹配) + +XfrmInStateProtoError: + 转换协议相关的错误 + (如SA密钥错误) + +XfrmInStateModeError: + 转换模式相关的错误 + +XfrmInStateSeqError: + 序列号错误 + 序列号超出窗口范围 + +XfrmInStateExpired: + 状态已过期 + +XfrmInStateMismatch: + 状态选项不匹配 + (如UDP封装类型不匹配) + +XfrmInStateInvalid: + 无效状态 + +XfrmInTmplMismatch: + 状态模板不匹配 + (如入站SA正确但SP规则错误) + +XfrmInNoPols: + 未找到状态的对应策略 + (如入站SA正确但无SP规则) + +XfrmInPolBlock: + 丢弃的策略 + +XfrmInPolError: + 错误的策略 + +XfrmAcquireError: + 状态未完全获取即被使用 + +XfrmFwdHdrError: + 转发路由禁止 + +XfrmInStateDirError: + 状态方向不匹配 + (输入路径查找到输出状态,预期是输入状态或者无方向) + +出站错误 +~~~~~~~~ +XfrmOutError: + 未匹配其他类别的所有错误 + +XfrmOutBundleGenError: + 捆绑包生成错误 + +XfrmOutBundleCheckError: + 捆绑包校验错误 + +XfrmOutNoStates: + 未找到状态 + +XfrmOutStateProtoError: + 转换协议特定错误 + +XfrmOutStateModeError: + 转换模式特定错误 + +XfrmOutStateSeqError: + 序列号错误 + (序列号溢出) + +XfrmOutStateExpired: + 状态已过期 + +XfrmOutPolBlock: + 丢弃策略 + +XfrmOutPolDead: + 失效策略 + +XfrmOutPolError: + 错误策略 + +XfrmOutStateInvalid: + 无效状态(可能已过期) + +XfrmOutStateDirError: + 状态方向不匹配(输出路径查找到输入状态,预期为输出状态或无方向) diff --git a/Documentation/translations/zh_CN/process/1.Intro.rst b/Documentation/translations/zh_CN/process/1.Intro.rst index 4f9284cbe33b..e314cce49d27 100644 --- a/Documentation/translations/zh_CN/process/1.Intro.rst +++ b/Documentation/translations/zh_CN/process/1.Intro.rst @@ -182,11 +182,11 @@ Andrew Morton, Andrew Price, Tsugikazu Shibata 和 Jochen Voß 。 可以获得所有版权所有者的同意(或者从内核中删除他们的代码)。因此,尤其是在 可预见的将来,许可证不大可能迁移到GPL的版本3。 -所有贡献给内核的代码都必须是合法的免费软件。因此,不接受匿名(或化名)贡献 -者的代码。所有贡献者都需要在他们的代码上“sign off(签发)”,声明代码可以 -在GPL下与内核一起分发。无法提供未被其所有者许可为免费软件的代码,或可能为 -内核造成版权相关问题的代码(例如,由缺乏适当保护的反向工程工作派生的代码) -不能被接受。 +所有贡献给内核的代码都必须是合法的免费软件。因此,出于这个原因,身份不明的 +贡献者或匿名贡献者提交的代码将不予接受。所有贡献者都需要在他们的代码上 +“sign off(签发)”,声明代码可以在GPL下与内核一起分发。无法提供未被其所有者 +许可为免费软件的代码,或可能为内核造成版权相关问题的代码(例如,由缺乏适当 +保护的反向工程工作派生的代码)不能被接受。 有关版权问题的提问在Linux开发邮件列表中很常见。这样的问题通常会得到不少答案, 但请记住,回答这些问题的人不是律师,不能提供法律咨询。如果您有关于Linux源代码 diff --git a/Documentation/translations/zh_CN/process/2.Process.rst b/Documentation/translations/zh_CN/process/2.Process.rst index e68c9de0f7f8..31b0e2c994f6 100644 --- a/Documentation/translations/zh_CN/process/2.Process.rst +++ b/Documentation/translations/zh_CN/process/2.Process.rst @@ -292,12 +292,11 @@ Quilt 是一个补丁管理系统,而不是源代码管理系统。它不会 一个潜在的危险,他们可能会被一堆电子邮件淹没、违反Linux列表上使用的约定, 或者两者兼而有之。 -大多数内核邮件列表都在vger.kernel.org上运行;主列表位于: +大多数内核邮件列表都托管在 kernel.org;主列表位于: - http://vger.kernel.org/vger-lists.html + https://subspace.kernel.org -不过,也有一些列表托管在别处;其中一些列表位于 -redhat.com/mailman/listinfo。 +其他地方也有邮件列表;请查看 MAINTAINERS 文件,获取与特定子系统相关的列表。 当然,内核开发的核心邮件列表是linux-kernel。这个列表是一个令人生畏的地方: 每天的信息量可以达到500条,噪音很高,谈话技术性很强,且参与者并不总是表现出 diff --git a/Documentation/translations/zh_CN/process/5.Posting.rst b/Documentation/translations/zh_CN/process/5.Posting.rst index 6c83a8f40310..ce37cf6a60e2 100644 --- a/Documentation/translations/zh_CN/process/5.Posting.rst +++ b/Documentation/translations/zh_CN/process/5.Posting.rst @@ -177,10 +177,21 @@ - Reported-by: 指定报告此补丁修复的问题的用户;此标记用于表示感谢。 + - Suggested-by: 表示该补丁思路由所提及的人提出,确保其创意贡献获得认可。 + 这有望激励他们在未来继续提供帮助。 + - Cc:指定某人收到了补丁的副本,并有机会对此发表评论。 在补丁中添加标签时要小心:只有Cc:才适合在没有指定人员明确许可的情况下添加。 +在补丁中添加上述标签时需谨慎,因为除了 Cc:、Reported-by: 和 Suggested-by:, +所有其他标签都需要被提及者的明确许可。对于这三个标签,若根据 lore 归档或提交 +历史记录,相关人员使用该姓名和电子邮件地址为 Linux 内核做出过贡献,则隐含许可 +已足够 -- 对于 Reported-by: 和 Suggested-by:,需确保报告或建议是公开进行的。 +请注意,从这个意义上讲,bugzilla.kernel.org 属于公开场合,但其使用的电子邮件地址 +属于私人信息;因此,除非相关人员曾在早期贡献中使用过这些邮箱,否则请勿在标签中 +公开它们。 + 寄送补丁 -------- diff --git a/Documentation/translations/zh_CN/process/6.Followthrough.rst b/Documentation/translations/zh_CN/process/6.Followthrough.rst index 2a127e737b6a..3d19c59ca6e4 100644 --- a/Documentation/translations/zh_CN/process/6.Followthrough.rst +++ b/Documentation/translations/zh_CN/process/6.Followthrough.rst @@ -49,6 +49,11 @@ 变。他们真的,几乎毫无例外地,致力于创造他们所能做到的最好的内核;他们并 没有试图给雇主的竞争对手造成不适。 + - 请准备好应对看似“愚蠢”的代码风格修改请求,以及将部分代码拆分到内核 + 共享模块的要求。维护者的职责之一是保持整体风格的一致性。有时这意味着, + 你在驱动中为解决某一问题而采用的巧妙取巧方案,实际上需要被提炼为通用的 + 内核特性,以便未来复用。 + 所有这些归根结底就是,当审阅者向您发送评论时,您需要注意他们正在进行的技术 评论。不要让他们的表达方式或你自己的骄傲阻止此事。当你在一个补丁上得到评论 时,花点时间去理解评论人想说什么。如果可能的话,请修复审阅者要求您修复的内 diff --git a/Documentation/translations/zh_CN/process/7.AdvancedTopics.rst b/Documentation/translations/zh_CN/process/7.AdvancedTopics.rst index 57beca02181c..92cc06dd5f4e 100644 --- a/Documentation/translations/zh_CN/process/7.AdvancedTopics.rst +++ b/Documentation/translations/zh_CN/process/7.AdvancedTopics.rst @@ -113,6 +113,8 @@ Git提供了一些强大的工具,可以让您重写开发历史。一个不 更改。在这方面 git request-pull 命令非常有用;它将按照其他开发人员所期望的 格式化请求,并检查以确保您已记得将这些更改推送到公共服务器。 +.. _cn_development_advancedtopics_reviews: + 审阅补丁 -------- @@ -126,8 +128,20 @@ Git提供了一些强大的工具,可以让您重写开发历史。一个不 的建议是:把审阅评论当成问题而不是批评。询问“在这条路径中如何释放锁?” 总是比说“这里的锁是错误的”更好。 +当出现分歧时,另一个有用的技巧是邀请他人参与讨论。如果交流数次后讨论陷入僵局, +可征求其他评审者或维护者的意见。通常,与某一评审者意见一致的人往往会保持沉默, +除非被主动询问。众人意见会产生成倍的影响力。 + 不同的开发人员将从不同的角度审查代码。部分人会主要关注代码风格以及代码行是 否有尾随空格。其他人会主要关注补丁作为一个整体实现的变更是否对内核有好处。 同时也有人会检查是否存在锁问题、堆栈使用过度、可能的安全问题、在其他地方 发现的代码重复、足够的文档、对性能的不利影响、用户空间ABI更改等。所有类型 的检查,只要它们能引导更好的代码进入内核,都是受欢迎和值得的。 + +使用诸如 ``Reviewed-by`` 这类特定标签并无严格要求。事实上,即便提供了标签,也 +更鼓励用平实的英文撰写评审意见,因为这样的内容信息量更大,例如,“我查看了此次 +提交中 A、B、C 等方面的内容,认为没有问题。”显然,以某种形式提供评审信息或回复 +是必要的,否则维护者将完全无法知晓评审者是否已查看过补丁! + +最后但同样重要的是,补丁评审可能会变成一个聚焦于指出问题的负面过程。请偶尔给予 +称赞,尤其是对新手贡献者! diff --git a/Documentation/translations/zh_CN/security/credentials.rst b/Documentation/translations/zh_CN/security/credentials.rst index 91c353dfb622..88fcd9152ffe 100644 --- a/Documentation/translations/zh_CN/security/credentials.rst +++ b/Documentation/translations/zh_CN/security/credentials.rst @@ -475,5 +475,5 @@ const指针上操作,因此不需要进行类型转换,但需要临时放弃 如 ``vfs_mkdir()`` 来实现。以下是一些进行此操作的位置: * ``sys_faccessat()``. - * ``do_coredump()``. + * ``vfs_coredump()``. * nfs4recover.c. diff --git a/Documentation/translations/zh_CN/security/self-protection.rst b/Documentation/translations/zh_CN/security/self-protection.rst index 3c8a68b1e1be..93de9cee5c1a 100644 --- a/Documentation/translations/zh_CN/security/self-protection.rst +++ b/Documentation/translations/zh_CN/security/self-protection.rst @@ -259,7 +259,7 @@ KALLSYSM,则会直接打印原始地址。 -------- 在释放内存时,最好对内存内容进行清除处理,以防止攻击者重用内存中以前 -的内容。例如,在系统调用返回时清除堆栈(CONFIG_GCC_PLUGIN_STACKLEAK), +的内容。例如,在系统调用返回时清除堆栈(CONFIG_KSTACK_ERASE), 在释放堆内容是清除其内容。这有助于防止许多未初始化变量攻击、堆栈内容 泄露、堆内容泄露以及使用后释放攻击(user-after-free)。 diff --git a/Documentation/translations/zh_CN/staging/index.rst b/Documentation/translations/zh_CN/staging/index.rst index bb55c81c84a3..6d68fabce175 100644 --- a/Documentation/translations/zh_CN/staging/index.rst +++ b/Documentation/translations/zh_CN/staging/index.rst @@ -13,6 +13,7 @@ .. toctree:: :maxdepth: 2 + speculation xz TODOList: @@ -21,6 +22,5 @@ TODOList: * lzo * remoteproc * rpmsg -* speculation * static-keys * tee diff --git a/Documentation/translations/zh_CN/staging/speculation.rst b/Documentation/translations/zh_CN/staging/speculation.rst new file mode 100644 index 000000000000..c36d33f67897 --- /dev/null +++ b/Documentation/translations/zh_CN/staging/speculation.rst @@ -0,0 +1,85 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/staging/speculation.rst + +:翻译: + + 崔巍 Cui Wei <chris.wei.cui@gmail.com> + +======== +推测执行 +======== + +本文档解释了推测执行的潜在影响,以及如何使用通用API来减轻不良影响。 + +------------------------------------------------------------------------------ + +为提高性能并减少平均延迟,许多现代处理器都采用分支预测等推测执行技术,执行结果 +可能在后续阶段被丢弃。 + +通常情况下,我们无法从架构状态(如寄存器内容)观察到推测执行。然而,在某些情况 +下从微架构状态观察其影响是可能的,例如数据是否存在于缓存中。这种状态可能会形成 +侧信道,通过观察侧信道可以提取秘密信息。 + +例如,在分支预测存在的情况下,边界检查可能被推测执行的代码忽略。考虑以下代码:: + + int load_array(int *array, unsigned int index) + { + if (index >= MAX_ARRAY_ELEMS) + return 0; + else + return array[index]; + } + +在arm64上,可以编译成如下汇编序列:: + + CMP <index>, #MAX_ARRAY_ELEMS + B.LT less + MOV <returnval>, #0 + RET + less: + LDR <returnval>, [<array>, <index>] + RET + +处理器有可能误预测条件分支,并推测性装载array[index],即使index >= MAX_ARRAY_ELEMS。 +这个值随后会被丢弃,但推测的装载可能会影响微架构状态,随后可被测量到。 + +涉及多个依赖内存访问的更复杂序列可能会导致敏感信息泄露。以前面的示例为基础,考虑 +以下代码:: + + int load_dependent_arrays(int *arr1, int *arr2, int index) + { + int val1, val2, + + val1 = load_array(arr1, index); + val2 = load_array(arr2, val1); + + return val2; + } + +根据推测,对load_array()的第一次调用可能会返回一个越界地址的值,而第二次调用将影响 +依赖于该值的微架构状态。这可能会提供一个任意读取原语。 + +缓解推测执行侧信道 +================== + +内核提供了一个通用API以确保即使在推测情况下也能遵守边界检查。受推测执行侧信道影响 +的架构应当实现这些原语。 + +<linux/nospec.h>中的array_index_nospec()辅助函数可用于防止信息通过侧信道泄漏。 + +调用array_index_nospec(index, size)将返回一个经过净化的索引值,即使在CPU推测执行 +条件下,该值也会被严格限制在[0, size)范围内。 + +这可以用来保护前面的load_array()示例:: + + int load_array(int *array, unsigned int index) + { + if (index >= MAX_ARRAY_ELEMS) + return 0; + else { + index = array_index_nospec(index, MAX_ARRAY_ELEMS); + return array[index]; + } + } |