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

TOMOYO Linux Cross Reference
Linux/Documentation/translations/zh_CN/core-api/watch_queue.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/watch_queue.rst
  6 
  7 :翻译:
  8 
  9 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
 10 
 11 :校译:
 12 
 13 司延腾 Yanteng Si <siyanteng@loongson.cn>
 14 吴想成 Wu Xiangcheng <bobwxc@email.cn>
 15 
 16 
 17 ============
 18 通用通知机制
 19 ============
 20 
 21 通用通知机制是建立在标准管道驱动之上的,它可以有效地将来自内核的通知消息拼接到用
 22 户空间打开的管道中。这可以与以下方面结合使用::
 23 
 24   * Key/keyring 通知
 25 
 26 通知缓冲区可以通过以下方式启用:
 27 
 28         “General setup”/“General notification queue”
 29         (CONFIG_WATCH_QUEUE)
 30 
 31 文档包含以下章节:
 32 
 33 .. contents:: :local:
 34 
 35 
 36 概述
 37 ====
 38 
 39 该设施以一种特殊模式打开的管道形式出现,管道的内部环形缓冲区用于保存内核生成的消
 40 息。然后通过read()读出这些消息。在此类管道上禁用拼接以及类似的操作,因为它们希望
 41 在某些情况下将其添加的内容还原到环中-这可能最终会与通知消息重叠。
 42 
 43 管道的所有者必须告诉内核它想通过该管道观察哪些源。只有连接到该管道上的源才会将消
 44 息插入其中。请注意,一个源可能绑定到多个管道,并同时将消息插入到所有管道中。
 45 
 46 还可以将过滤器放置在管道上,以便在不感兴趣时可以忽略某些源类型和子事件。
 47 
 48 如果环中没有可用的插槽,或者没有预分配的消息缓冲区可用,则将丢弃消息。在这两种情
 49 况下,read()都会在读取缓冲区中当前的最后一条消息后,将WATCH_META_LOSS_NOTIFICATION
 50 插入到输出缓冲区中。
 51 
 52 请注意,当生成一个通知时,内核不会等待消费者收集它,而是继续执行。这意味着可以在
 53 持有自旋锁的同时生成通知,并且还可以保护内核不被用户空间故障无限期地阻碍。
 54 
 55 
 56 消息结构
 57 ========
 58 
 59 通知消息由一个简短的头部开始::
 60 
 61         struct watch_notification {
 62                 __u32   type:24;
 63                 __u32   subtype:8;
 64                 __u32   info;
 65         };
 66 
 67 “type”表示通知记录的来源,“subtype”表示该来源的记录类型(见下文观测源章节)。该类
 68 型也可以是“WATCH_TYPE_META”。这是一个由观测队列本身在内部生成的特殊记录类型。有两
 69 个子类型:
 70 
 71   * WATCH_META_REMOVAL_NOTIFICATION
 72   * WATCH_META_LOSS_NOTIFICATION
 73 
 74 第一个表示安装了观察的对象已被删除或销毁,第二个表示某些消息已丢失。
 75 
 76 “info”表示一系列东西,包括:
 77 
 78   * 消息的长度,以字节为单位,包括头(带有WATCH_INFO_LENGTH的掩码,并按
 79     WATCH_INFO_LENGTH__SHIFT移位)。这表示记录的大小,可能在8到127字节之间。
 80 
 81   * 观测ID(带有WATCH_INFO_ID掩码,并按WATCH_INFO_ID__SHIFT移位)。这表示观测的主
 82     叫ID,可能在0到255之间。多个观测组可以共享一个队列,这提供了一种区分它们的方法。
 83 
 84   * 特定类型的字段(WATCH_INFO_TYPE_INFO)。这是由通知生产者设置的,以指示类型和
 85     子类型的某些特定含义。
 86 
 87 除长度外,信息中的所有内容都可以用于过滤。
 88 
 89 头部后面可以有补充信息。此格式是由类型和子类型决定的。
 90 
 91 
 92 观测列表(通知源)API
 93 =====================
 94 
 95 “观测列表“是订阅通知源的观测者的列表。列表可以附加到对象(比如键或超级块),也可
 96 以是全局的(比如对于设备事件)。从用户空间的角度来看,一个非全局的观测列表通常是
 97 通过引用它所属的对象来引用的(比如使用KEYCTL_NOTIFY并给它一个密钥序列号来观测特定
 98 的密钥)。
 99 
100 为了管理观测列表,提供了以下函数:
101 
102   * ::
103 
104         void init_watch_list(struct watch_list *wlist,
105                              void (*release_watch)(struct watch *wlist));
106 
107     初始化一个观测列表。 如果 ``release_watch`` 不是NULL,那么这表示当watch_list对
108     象被销毁时,应该调用函数来丢弃观测列表对被观测对象的任何引用。
109 
110   * ``void remove_watch_list(struct watch_list *wlist);``
111 
112     这将删除订阅watch_list的所有观测,并释放它们,然后销毁watch_list对象本身。
113 
114 
115 观测队列(通知输出)API
116 =======================
117 
118 “观测队列”是由应用程序分配的用以记录通知的缓冲区,其工作原理完全隐藏在管道设备驱
119 动中,但必须获得对它的引用才能设置观测。可以通过以下方式进行管理:
120 
121   * ``struct watch_queue *get_watch_queue(int fd);``
122 
123     由于观测队列在内核中通过实现缓冲区的管道的文件描述符表示,用户空间必须通过系
124     统调用传递该文件描述符,这可以用于从系统调用中查找指向观测队列的不透明指针。
125 
126   * ``void put_watch_queue(struct watch_queue *wqueue);``
127 
128     该函数用以丢弃从 ``get_watch_queue()`` 获得的引用。
129 
130 
131 观测订阅API
132 ===========
133 
134 “观测”是观测列表上的订阅,表示观测队列,从而表示应写入通知记录的缓冲区。观测队列
135 对象还可以携带该对象的过滤规则,由用户空间设置。watch结构体的某些部分可以由驱动程
136 序设置::
137 
138         struct watch {
139                 union {
140                         u32             info_id;        /* 在info字段中进行OR运算的ID */
141                         ...
142                 };
143                 void                    *private;       /* 被观测对象的私有数据 */
144                 u64                     id;             /* 内部标识符 */
145                 ...
146         };
147 
148 ``info_id`` 值是从用户空间获得并按WATCH_INFO_ID__SHIFT移位的8位数字。当通知写入关
149 联的观测队列缓冲区时,这将与struct watch_notification::info的WATCH_INFO_ID字段进
150 行或运算。
151 
152 ``private`` 字段是与watch_list相关联的驱动程序数据,并由 ``watch_list::release_watch()``
153 函数清除。
154 
155 ``id`` 字段是源的ID。使用不同ID发布的通知将被忽略。
156 
157 提供以下函数来管理观测:
158 
159   * ``void init_watch(struct watch *watch, struct watch_queue *wqueue);``
160 
161     初始化一个观测对象,把它的指针设置到观察队列中,使用适当的限制来避免死锁。
162 
163   * ``int add_watch_to_object(struct watch *watch, struct watch_list *wlist);``
164 
165     将观测订阅到观测列表(通知源)。watch结构体中的driver-settable字段必须在调用
166     它之前设置。
167 
168   * ::
169 
170         int remove_watch_from_object(struct watch_list *wlist,
171                                      struct watch_queue *wqueue,
172                                      u64 id, false);
173 
174     从观测列表中删除一个观测,该观测必须与指定的观测队列(``wqueue``)和对象标识
175     符(``id``)匹配。通知(``WATCH_META_REMOVAL_NOTIFICATION``)被发送到观测队列
176     表示该观测已被删除。
177 
178   * ``int remove_watch_from_object(struct watch_list *wlist, NULL, 0, true);``
179 
180     从观测列表中删除所有观测。预计这将被称为销毁前的准备工作,届时新的观测将无法
181     访问观测列表。通知(``WATCH_META_REMOVAL_NOTIFICATION``)被发送到每个订阅观测
182     的观测队列,以表明该观测已被删除。
183 
184 
185 通知发布API
186 ===========
187 
188 要将通知发布到观测列表以便订阅的观测可以看到,应使用以下函数::
189 
190         void post_watch_notification(struct watch_list *wlist,
191                                      struct watch_notification *n,
192                                      const struct cred *cred,
193                                      u64 id);
194 
195 应预先设置通知格式,并应传入一个指向头部(``n``)的指针。通知可能大于此值,并且缓
196 冲槽为单位的大小在 ``n->info & WATCH_INFO_LENGTH`` 中注明。
197 
198 ``cred`` 结构体表示源(对象)的证书,并传递给LSM,例如SELinux,以允许或禁止根据该队
199 列(对象)的证书在每个单独队列中记录注释。
200 
201 ``id`` 是源对象ID(如密钥上的序列号)。只有设置相同ID的观测才能看到这个通知。
202 
203 
204 观测源
205 ======
206 
207 任何特定的缓冲区都可以从多个源获取信息。 这些源包括:
208 
209   * WATCH_TYPE_KEY_NOTIFY
210 
211     这种类型的通知表示密钥和密钥环的变化,包括密钥环内容或密钥属性的变化。
212 
213     更多信息请参见Documentation/security/keys/core.rst。
214 
215 
216 事件过滤
217 ========
218 
219 当创建观测队列后,我们可以应用一组过滤器以限制接收的事件::
220 
221         struct watch_notification_filter filter = {
222                 ...
223         };
224         ioctl(fd, IOC_WATCH_QUEUE_SET_FILTER, &filter)
225 
226 过滤器的描述的类型变量是::
227 
228         struct watch_notification_filter {
229                 __u32   nr_filters;
230                 __u32   __reserved;
231                 struct watch_notification_type_filter filters[];
232         };
233 
234 其中“nr_filters”表示filters[]数组中过滤器的数量,而“__reserved”应为0。
235 “filter”数组有以下类型的元素::
236 
237         struct watch_notification_type_filter {
238                 __u32   type;
239                 __u32   info_filter;
240                 __u32   info_mask;
241                 __u32   subtype_filter[8];
242         };
243 
244 其中:
245 
246   * ``type`` 是过滤的事件类型,应类似于“WATCH_TYPE_KEY_NOTIFY”。
247 
248   * ``info_filter`` 与 ``info_mask`` 充当通知记录的信息字段的过滤器,只有在以下情
249     况,通知才会写入缓冲区::
250 
251         (watch.info & info_mask) == info_filter
252 
253     例如,这可以用于忽略不在一个挂载树上的观测点的事件。
254 
255   * ``subtype_filter`` 是一个位掩码,表示感兴趣的子类型。subtype_filter[0]的
256     bit[0]对应子类型0,bit[1]对应子类型1,以此类推。
257 
258 若ioctl()的参数为NULL,则过滤器将被移除,并且来自观测源的所有事件都将通过。
259 
260 
261 用户空间代码示例
262 ================
263 
264 缓冲区的创建如下所示::
265 
266         pipe2(fds, O_TMPFILE);
267         ioctl(fds[1], IOC_WATCH_QUEUE_SET_SIZE, 256);
268 
269 它可以被设置成接收密钥环变化的通知::
270 
271         keyctl(KEYCTL_WATCH_KEY, KEY_SPEC_SESSION_KEYRING, fds[1], 0x01);
272 
273 然后,这些通知可以被如下方式所使用::
274 
275         static void consumer(int rfd, struct watch_queue_buffer *buf)
276         {
277                 unsigned char buffer[128];
278                 ssize_t buf_len;
279 
280                 while (buf_len = read(rfd, buffer, sizeof(buffer)),
281                        buf_len > 0
282                        ) {
283                         void *p = buffer;
284                         void *end = buffer + buf_len;
285                         while (p < end) {
286                                 union {
287                                         struct watch_notification n;
288                                         unsigned char buf1[128];
289                                 } n;
290                                 size_t largest, len;
291 
292                                 largest = end - p;
293                                 if (largest > 128)
294                                         largest = 128;
295                                 memcpy(&n, p, largest);
296 
297                                 len = (n->info & WATCH_INFO_LENGTH) >>
298                                         WATCH_INFO_LENGTH__SHIFT;
299                                 if (len == 0 || len > largest)
300                                         return;
301 
302                                 switch (n.n.type) {
303                                 case WATCH_TYPE_META:
304                                         got_meta(&n.n);
305                                 case WATCH_TYPE_KEY_NOTIFY:
306                                         saw_key_change(&n.n);
307                                         break;
308                                 }
309 
310                                 p += len;
311                         }
312                 }
313         }

~ [ 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