在Linux系统中, 无论何时设备从系统中增删, 都会触发一个"热插拔"事件. 这意味着内核会调用用户空间程序 /sbin/hotplug. 这个程序通常是一个非常简短的Bash脚本, 它会依次执行位于 /etc/hot-plug.d/ 目录树中的多个脚本文件. 对于大多数Linux发行版, 这个脚本的内容大致如下:
DIR="/etc/hotplug.d"
for I in "${DIR}/$1/*.hotplug" "${DIR}/"default/*.hotplug
do
if [ -f $I ]; then
test -x $I && $I $1
fi
done
exit 1
?
换句话说, 这个脚本会搜索所有以 .hotplug 为扩展名的文件, 并将它们调用, 并传递一系列预先设置好的环境变量, 这些环境变量由内核提供. 更详细的信息可以参考脚本注释或 hotplug(8) 手册页.
需要注意的是, 不论是kobject的创建还是销毁都会触发热插拔事件. hotplug脚本会被用一个包含事件名称的命令行参数调用. 核心内核以及相关子系统会预先设置一系列环境变量, 包括:
ACTION
该环境变量的值为add或remove, 取决于kobject是被创建还是销毁.
DEVPATH
指向在sysfs文件系统中mlarg目录下的对应节点的路径. 需要注意的是, 这个路径不包括sysfs加载点, 所以需要由用户空间程序自行构造.
SEQNUM
表示此热插拔事件的顺序编号. 一个64位的递增数, 这样可以确保热插拔事件在用户空间的处理顺序与内核处理顺序保持一致.
SUBSYSTEM
与调用hotplug脚本的命令行参数相同, 代表关联的子系统名称.
除此之外, 根据子系统类型, 还会有额外的环境变量被添加到hotplug调用中. 这些变量通常由各子系统在热插拔回调函数中自行设置, 而这些回调函数是由struct kset_hotplug_ops的name函数指定的. 如果name函数不存在或者未被调用, 则使用kset自身的名称.
典型的例子包括PCI总线和设备总线等子系统. 例如, 根据总线类型, 它们会添加不同的环境变量, 以便用户空间能够自动加载需要的模块来处理新发现的设备. 不同总线类型的具体实现方式如下: