~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/Documentation/translations/zh_CN/core-api/padata.rst

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 .. SPDX-License-Identifier: GPL-2.0
  2 
  3 .. include:: ../disclaimer-zh_CN.rst
  4 
  5 :Original: Documentation/core-api/padata.rst
  6 
  7 :翻译:
  8 
  9  司延腾 Yanteng Si <siyanteng@loongson.cn>
 10 
 11 .. _cn_core_api_padata.rst:
 12 
 13 ==================
 14 padata并行执行机制
 15 ==================
 16 
 17 :日期: 2020年5月
 18 
 19 Padata是一种机制,内核可以通过此机制将工作分散到多个CPU上并行完成,同时
 20 可以选择保持它们的顺序。
 21 
 22 它最初是为IPsec开发的,它需要在不对这些数据包重新排序的其前提下,为大量的数
 23 据包进行加密和解密。这是目前padata的序列化作业支持的唯一用途。
 24 
 25 Padata还支持多线程作业,将作业平均分割,同时在线程之间进行负载均衡和协调。
 26 
 27 执行序列化作业
 28 ==============
 29 
 30 初始化
 31 ------
 32 
 33 使用padata执行序列化作业的第一步是建立一个padata_instance结构体,以全面
 34 控制作业的运行方式::
 35 
 36     #include <linux/padata.h>
 37 
 38     struct padata_instance *padata_alloc(const char *name);
 39 
 40 'name'即标识了这个实例。
 41 
 42 然后,通过分配一个padata_shell来完成padata的初始化::
 43 
 44    struct padata_shell *padata_alloc_shell(struct padata_instance *pinst);
 45 
 46 一个padata_shell用于向padata提交一个作业,并允许一系列这样的作业被独立地
 47 序列化。一个padata_instance可以有一个或多个padata_shell与之相关联,每个
 48 都允许一系列独立的作业。
 49 
 50 修改cpumasks
 51 ------------
 52 
 53 用于运行作业的CPU可以通过两种方式改变,通过padata_set_cpumask()编程或通
 54 过sysfs。前者的定义是::
 55 
 56     int padata_set_cpumask(struct padata_instance *pinst, int cpumask_type,
 57                            cpumask_var_t cpumask);
 58 
 59 这里cpumask_type是PADATA_CPU_PARALLEL(并行)或PADATA_CPU_SERIAL(串行)之一,其中并
 60 行cpumask描述了哪些处理器将被用来并行执行提交给这个实例的作业,串行cpumask
 61 定义了哪些处理器被允许用作串行化回调处理器。 cpumask指定了要使用的新cpumask。
 62 
 63 一个实例的cpumasks可能有sysfs文件。例如,pcrypt的文件在
 64 /sys/kernel/pcrypt/<instance-name>。在一个实例的目录中,有两个文件,parallel_cpumask
 65 和serial_cpumask,任何一个cpumask都可以通过在文件中回显(echo)一个bitmask
 66 来改变,比如说::
 67 
 68     echo f > /sys/kernel/pcrypt/pencrypt/parallel_cpumask
 69 
 70 读取其中一个文件会显示用户提供的cpumask,它可能与“可用”的cpumask不同。
 71 
 72 Padata内部维护着两对cpumask,用户提供的cpumask和“可用的”cpumask(每一对由一个
 73 并行和一个串行cpumask组成)。用户提供的cpumasks在实例分配时默认为所有可能的CPU,
 74 并且可以如上所述进行更改。可用的cpumasks总是用户提供的cpumasks的一个子集,只包
 75 含用户提供的掩码中的在线CPU;这些是padata实际使用的cpumasks。因此,向padata提
 76 供一个包含离线CPU的cpumask是合法的。一旦用户提供的cpumask中的一个离线CPU上线,
 77 padata就会使用它。
 78 
 79 改变CPU掩码的操作代价很高,所以不应频繁更改。
 80 
 81 运行一个作业
 82 -------------
 83 
 84 实际上向padata实例提交工作需要创建一个padata_priv结构体,它代表一个作业::
 85 
 86     struct padata_priv {
 87         /* Other stuff here... */
 88         void                    (*parallel)(struct padata_priv *padata);
 89         void                    (*serial)(struct padata_priv *padata);
 90     };
 91 
 92 这个结构体几乎肯定会被嵌入到一些针对要做的工作的大结构体中。它的大部分字段对
 93 padata来说是私有的,但是这个结构在初始化时应该被清零,并且应该提供parallel()和
 94 serial()函数。在完成工作的过程中,这些函数将被调用,我们马上就会遇到。
 95 
 96 工作的提交是通过::
 97 
 98     int padata_do_parallel(struct padata_shell *ps,
 99                            struct padata_priv *padata, int *cb_cpu);
100 
101 ps和padata结构体必须如上所述进行设置;cb_cpu指向作业完成后用于最终回调的首选CPU;
102 它必须在当前实例的CPU掩码中(如果不是,cb_cpu指针将被更新为指向实际选择的CPU)。
103 padata_do_parallel()的返回值在成功时为0,表示工作正在进行中。-EBUSY意味着有人
104 在其他地方正在搞乱实例的CPU掩码,而当cb_cpu不在串行cpumask中、并行或串行cpumasks
105 中无在线CPU,或实例停止时,则会出现-EINVAL反馈。
106 
107 每个提交给padata_do_parallel()的作业将依次传递给一个CPU上的上述parallel()函数
108 的一个调用,所以真正的并行是通过提交多个作业来实现的。parallel()在运行时禁用软
109 件中断,因此不能睡眠。parallel()函数把获得的padata_priv结构体指针作为其唯一的参
110 数;关于实际要做的工作的信息可能是通过使用container_of()找到封装结构体来获得的。
111 
112 请注意,parallel()没有返回值;padata子系统假定parallel()将从此时开始负责这项工
113 作。作业不需要在这次调用中完成,但是,如果parallel()留下了未完成的工作,它应该准
114 备在前一个作业完成之前,被以新的作业再次调用
115 
116 序列化作业
117 ----------
118 
119 当一个作业完成时,parallel()(或任何实际完成该工作的函数)应该通过调用通知padata此
120 事::
121 
122     void padata_do_serial(struct padata_priv *padata);
123 
124 在未来的某个时刻,padata_do_serial()将触发对padata_priv结构体中serial()函数的调
125 用。这个调用将发生在最初要求调用padata_do_parallel()的CPU上;它也是在本地软件中断
126 被禁用的情况下运行的。
127 请注意,这个调用可能会被推迟一段时间,因为padata代码会努力确保作业按照提交的顺序完
128 成。
129 
130 销毁
131 ----
132 
133 清理一个padata实例时,可以预见的是调用两个free函数,这两个函数对应于分配的逆过程::
134 
135     void padata_free_shell(struct padata_shell *ps);
136     void padata_free(struct padata_instance *pinst);
137 
138 用户有责任确保在调用上述任何一项之前,所有未完成的工作都已完成。
139 
140 运行多线程作业
141 ==============
142 
143 一个多线程作业有一个主线程和零个或多个辅助线程,主线程参与作业,然后等待所有辅助线
144 程完成。padata将作业分割成称为chunk的单元,其中chunk是一个线程在一次调用线程函数
145 中完成的作业片段。
146 
147 用户必须做三件事来运行一个多线程作业。首先,通过定义一个padata_mt_job结构体来描述
148 作业,这在接口部分有解释。这包括一个指向线程函数的指针,padata每次将作业块分配给线
149 程时都会调用这个函数。然后,定义线程函数,它接受三个参数: ``start`` 、 ``end`` 和 ``arg`` ,
150 其中前两个参数限定了线程操作的范围,最后一个是指向作业共享状态的指针,如果有的话。
151 准备好共享状态,它通常被分配在主线程的堆栈中。最后,调用padata_do_multithreaded(),
152 它将在作业完成后返回。
153 
154 接口
155 ====
156 
157 该API在以下内核代码中:
158 
159 include/linux/padata.h
160 
161 kernel/padata.c

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php