肥仔教程网

SEO 优化与 Web 开发技术学习分享平台

linux udev详解4-Storage Instantiation Daemon(2)

此文章翻译自:Storage Instantiation Daemon (sid-project.github.io)。

强烈推荐看下此文章,不仅对之前的udev内容做了部分补充,更能加强对udev的理解。工作中涉及有udev的道友可以看下原文。

先决条件

udevd内置命令-sid

在udevd和存储实例化守护程序(SID)之间建立一个通信通道,以便能够在两者之间有效地交换信息。

udevd支持实现内置命令,这些命令在udevd启动时初始化,并在udevd停止时完成。这样udevd在处理每个uevent时不需要fork新进程,就像在udev规则中引用外部命令时。

在udev规则中调用内置命令方式与调用任何外部命令非常相似,在规则中使用RUN{builtin}或IMPORT{builtin}即可。

注意:udevd内置命令使用内部模块化接口直接集成到udevd源代码中。udevd不支持外部和动态加载的模块实现此功能。

udevd和SID之间的通道使用本地流和面向连接的socket IPC实现(AF_UNIX/AF_LOCAL socket域,SOCK_STREAM socket类型)。

如果udevd创建了一个新的worker进程,连接将在第一次调用sid内置命令时建立,并保持打开状态,直到worker进程退出(或在超时的情况下被udevd进程终止)。

由于我们使用流和面向连接的通道,接收方(SID)可以检测到对方(worker进程)的断连。这样,SID能够检测到worker进程超时并在意外发生断连时触发后续的回退操作。

sid支持的子命令

  • sid active

目的: 检查SID的可用性。

输入: None

输出: SID_BRIDGE_STATUS=<status>,其中<status>有以下值:

  • active:表示SID的兼容版本正在运行,
  • inactive:表示未运行,
  • incompatible:表示SID正在运行,但其版本与当前sid udevd内置命令不兼容。

示例:

IMPORT{builtin}="sid active"
ENV{SID_BRIDGE_STATUS}=="active", ...
ENV{SID_BRIDGE_STATUS}=="incompatible", ...
ENV{SID_BRIDGE_STATUS}=="inactive", ...
  • sid scan

目的: 执行SID的识别和扫描程序、更新SID数据库、执行相关操作;

输入: 以KEY=VALUE格式表示的udev环境;

输出: 以KEY=VALUE格式表示的环境,其中包含changed或added的项目。

示例:

 IMPORT{builtin}="sid scan"
  • sid checkpoint <checkpoint_name> [<key> ...]

目的: 向SID发送关于匹配checkpoint的消息。

输入: 在匹配udev规则时达到的<checkpoint_name>。还可以传递一个从当前udev环境引用的键列表(或者使用all关键字表示所有可用键)。除了checkpoint名称本身,该命令还将从当前udev的每个设备环境向SID发送选定的KEY=VALUE。有一个预留的checkpoint:complete,用于通知SID udev规则中的udev处理即将结束。

输出: None。

注: 安装或启用其他udev规则可以使用checkpoint进行调试,这些规则将在SID执行时执行,以便SID能够跟踪uevent处理的进展。

示例

PROGRAM{builtin}="sid checkpoint my_checkpoint A B C" 
RUN{builtin}="sid checkpoint complete"
  • sid version

目的: 返回sid udevd内置命令和SID程序的版本信息。

输入: None。

输出: 一组KEY=VALUE:

  • SID_PROTOCOL=<protocol_version>
  • SID_MAJOR=<major_version>
  • SID_MINOR=<minor_version>
  • SID_RELEASE=<release_version>
  • SID_BUILTIN_PROTOCOL=<protocol_version>
  • SID_BUILTIN_MAJOR=<major_version>
  • SID_BUILTIN_MINOR=<minor_version>
  • SID_BUILTIN_RELEASE=<release_version>

注: 尽管可以在udev规则中调用sid version,但更合理的是将其作为udevadm test-builtin命令的一部分进行调用,用于收集当前系统环境的调试和版本信息。请注意,udevadm test-builtin命令需要给定一个现有设备的sysfs路径作为参数。sid version内置命令不与任何设备绑定,因为它只收集版本信息,所以可以在这里使用任意现有的sysfs路径来满足要求。

示例:

# udevadm test-builtin "sid version" /sys/kernel
SID_PROTOCOL=1
SID_MAJOR=0
SID_MINOR=0
SID_RELEASE=1
SID_BUILTIN_PROTOCOL=1
SID_BUILTIN_MAJOR=0
SID_BUILTIN_MINOR=0
SID_BUILTIN_RELEASE=1

增强synthetic-uevents

在处理uevents时需要考虑并不是所有uevents都是直接在内核中触发的,还有用户空间触发的合成uevents(如将事件写入/sys/.../uevent文件)。为了能够更好地区分synthetic-uevents和kernel-uevents,需要增强synthetic-uevent接口。

  1. 内核增加支持增强的synthetic-uevents特性

增强synthetic-uevents接口在写入/sys/…/uevent文件时可以传递附加参数。

提议是在事件名称中传递一个唯一标识符,将生成的uevent标记为事务的一部分。该事务可以跨越一个或多个uevents。该标识符将作为环境变量出现在生成的uevent中。如果我们使用一个标识符和多个uevents,我们将它们逻辑上组合在一起 - 在这种情况下,任何读取这些uevents的用户空间进程都可以观察和/或收集组中的所有成员。此外,通过这种方式,可以与合成uevent处理进行同步,并且在继续后续处理之前,我们可以等待组中的所有更改稳定下来。

以前无法等待单个uevent处理完成,只能使用udevadm settle命令等待所有uevent处理完,该命令将等待很多无关的uevents。

为了向后兼容,synthetic-uevents不需要标识符,内核只是自动添加一个值为零的标识符。

注意:使用UUID表示标识符 ,UUID可以使用工具生成(如util-linux工具集的uuidgen)或使用各种库(如util-linux的libuuid或libsystemd的sd-id128)。

用户空间进程触发synthetic-uevents可以追加环境变量,追加的KEY=VALUE环境变量列表需要在标识符之后。另外KEY和VALUE要求必须是字母和数字,每个KEY=VALUE之间用空格隔开。为了避免现有udev环境变量键的名称冲突,写/sys/.../uevent文件时内核将自动在每个KEY前添加SYNTH_。

以下是增强的synthetic-uevent接口使用示例:

# uuid=$(uuidgen)

# echo $uuid
4f60b88c-3052-4daa-8904-2e4efe8563ef

# echo "change 4f60b88c-3052-4daa-8904-2e4efe8563ef A=1 B=abc" > /sys/block/sda/uevent
# 监听输出结果
#udevadm monitor -k -u  -p
ACTION=change
DEVPATH=/devices/pci0000:00/0000:00:10.0/host32/target32:0:0/32:0:0:0/block/sda
SUBSYSTEM=block
SYNTH_UUID=0b591ea4-10d4-431a-b663-7528c6e9043b
SYNTH_ARG_A=1
SYNTH_ARG_B=abc

sys/.../uevent接口仍然保持向后兼容,可以只写入事件(add\change等)触发,不追加额外的变量仍然可以工作

# echo "change" > /sys/block/sda/uevent
# udevadm monitor --kernel --property
DEVPATH=/devices/pci0000:00/0000:00:08.0/virtio4/host2/target2:0:0/2:0:0:0/block/sda
DEVTYPE=disk
MAJOR=8
MINOR=0
SEQNUM=2028
SUBSYSTEM=block
SYNTH_UUID=0

上面示例中SYNTH_UUID=0是内核自动添加的,即使在写入/sys/.../uevent来生成synthetic-uevent时没有使用额外的参数,仍然可以在处理它们时区分kernel-uevent和synthetic-uevents,synthetic-uevents始终包含SYNTH_UUID键。

注意:增强的synthetic-uevent接口kernel版本4.13才开始支持。

  1. OPTIONS+="watch"规则增强的synthetic-uevents特性

作为应用OPTIONS+="watch"规则的结果生成的所有synthetic-uevents将包含以下KEY=VALUE对:

SYNTH_UUID="00000000-0000-0000-0000-00000000000" 
SYNTH_ARG_UDEV_WATCH="1" 

这意味着,每次udev写入/sys/.../uevent文件生成synthetic-uevents时,它将使用以下字符串触发uevent:

change 00000000-0000-0000-0000-00000000000 UDEV_WATCH=1 

在基于OPTIONS="watch"规则生成的synthetic-uevents中使用空UUID是因为这里没有任何作用,预留以后使用。

  1. udevadm trigger增强的synthetic-uevents特性

udevadm trigger调用生成的所有合成uevents将包含以下KEY=VALUE对:

SYNTH_UUID="<uuid>" 
SYNTH_ARG_UDEV_TRIGGER="1"


这意味着,每次udev写入/sys/.../uevent文件生成synthetic-uevents时,将使用此字符串触发uevent:

<action_name> <uuid> UDEV_TRIGGER=1                 

<action_name>是使用-c,--action=ACTION参数提供的ACTION。 <uuid>通过使用新的--uuid=UUID参数传入。 UUID然后用于触发所有的uevents,所有的uevents按照此UUID组合成单个事务。如果未指定UUID,则udevadm trigger会生成一个随机UUID。

此外,udevadm trigger有个新的参数-wait-uevent,作用是在退出之前等待udev中的所有相关uevent处理(包括所有udev规则处理)完成。

例如,要为所有属于块子系统的设备触发change uevent,并在退出udevadm trigger之前等待udev中的所有相关uevent处理完成,命令如下:

udevadm trigger --subsystem-match block --action change --wait-uevent

要为所有属于块子系统的设备触发change uevent,并使所有生成的uevents在uevent环境中设置UUID为
6cab53e2-b9c9-4c43-9d1d-0d8673fb62b0,命令如下:

udevadm trigger --subsystem-match block --action change --uuid 6cab53e2-b9c9-4c43-9d1d-0d8673fb62b0
  1. libudev支持增强synthetic-uevents

libudev库包含有生成synthetic-uevent的函数,函数原型如下:

int udev_device_synth_uevent(struct udev_device *udev_device, const char *action, bool wait, unsigned long long timeout);

该接口为udev_device生成类型为action的synthetic-uevent。如果wait为true,函数将在内部设置uevent监视器以等待对应的udev uevent,并在收到uevent或timeout时退出。

使用device_synth_uevent函数生成的所有synthetic-uevents都将包含以下KEY=VALUE对:

SYNTH_UUID="<uuid>" 
SYNTH_ARG_LIBUDEV_TRIGGER="1"

这意味着,每次在此场景中libudev写入/sys/.../uevent文件以生成synthetic-uevents时,将使用此字符串触发uevent:

<action_name> <uuid> LIBUDEV_TRIGGER=1

未来可能会提供更多的函数来扩展此功能,并通过libudev库提供类似于udevadm trigger的功能。

最终,各种工具和用户空间组件建议使用这个接口,而不是依赖于OPTIONS+="watch"规则。

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言