Linux 热插拔（Hot Plug）处理机制系列

l

l
udev创建了相应的设备节点之后，会将这一消息通知hal的守护程序(hald)。当然udev还得保证新创建的设备节点可以被普通用户访问。

l
hotplug装入了相应的内核模块之后，会把这一消息通知给hald

l
hald在受到hotplugudev发出的消息之后，认为新硬件已经正式被系统认可了。此时它会通过一系列精心编写的规则文件（就是传说中的xxx-policy.fdi），把发现新硬件的消息通过dbus发送出去，同时还会调用update-fstabfstab-sync来更新/etc/fstab，为相应的设备节点创建适合的挂载点。

l

l
hald会自己监视CDROM，并且将光盘托架开合的消息通过dbus发出去。

l

l
hotplug

hotplug 包和内核里的hotplug模块不是一回事，2.6内核里的pci_hotplug.ko是一个内核模块，而hotplug包是用来处理内核产生的hotplug事件。这个软件包还在引导时检测现存的硬件并在运行的内核中加载相关模块。

/etc/hotplug/*.rc 这些脚本用于冷插拔(检测和激活在系统启动时已经存在的硬件)。它们被 hotplug 初始化脚本调用。*.rc 脚本会尝试恢复系统引导时丢失的热插拔事件，举例来说，内核没有挂载根文件系统。

/etc/hotplug/*.agent这些脚本将被 hotplug

/sbin/hotplug内核默认情况下将在内核态的某些事情发生变化时(如硬件的插入和拔出)调用此脚本。

l
udev

2.6内核里，使用了udev来取代hotplug。据udev的作者Greg K.H说，之所以废弃了hotplug原因是sysfs的出现，这个东西会产生非常多的hotplug事件，远远超过了2.4的内核（只要实现了了kobject模型的设备驱动都回产生该事件）。所以hotplug变得复杂，而且因为hotplug都是bash所写，所以开始变得没有效率。于是出现了一个名叫hotplug-ng的项目，就是为了解决这个过于复杂以及缺乏效率的问题，ng应该是next generation的意思。但这个项目目前为止还不能胜任角色，所以udev挺身而出，充当了救火队员。

udev 完全在用户态 (userspace) 工作，利用设备加入或移除时内核所发送的hotplug 事件 (event) 来工作。关于设备的详细信息是由内核输出 (export) 到位于 /sys  sysfs 文件系统的。所有的设备命名策略、权限控制和事件处理都是在用户态下完成的。与此相反，devfs 是作为内核的一部分工作的。

udev 初始化脚本负责在 Linux 启动的时候创建设备节点，该脚本首先将 /sbin/udevsend 注册为热插拔事件处理程序。热插拔事件(随后将讨论)本不应该在这个阶段发生，注册 udev 只是为了以防万一。然后 udevstart 遍历 /sys 文件系统，并在 /dev 目录下创建符合描述的设备。例如，/sys/class/tty/vcs/dev 里含有"7:0"字符串，udevstart 就根据这个字符串创建主设备号为 7 、次设备号为 0  /dev/vcs 设备。udevstart 创建的每个设备的名字和权限由 /etc/udev/rules.d/ 目录下的文件指定的规则来设置。如果 udev 找不到所创建设备的权限文件，就将其权限设置为缺省的 660 ，所有者为 root:root 。上面的步骤完成后，那些已经存在并且已经内建驱动的设备就可以使用了。

l
HAL

HAL位于设备驱动程序和应用程序之间。

l
D-BUS

D-BUS 是一个大有前途的消息总线和活动系统，正开始深入地渗透到 Linux 桌面之中。D-BUS 本质上是进程间通信（inter-process communication）（IPC）的一个实现，设计用于桌面应用程序和OS 通信。

l

lspci

lshal 列出系统硬件设备。

Usbmodules

Hot Plug Greg Kroah-Hartman

Hot-pluggable devices have been created to solve a number of user needs. On laptop computers, PCMCIA devices were designed to allow the user to swap cards while the computer was still running. This allowed people to change network adaptors, memory cards and even disk drives without shutting down the machine.
The success of this led to the creation of the USB and IEEE1394 (FireWire) buses. These designs allow for peripherals to be attached and removed at any point. They also were created to try to move systems away from the ISA bus to a full Plug-and-Play-type system.
From the operating system's point of view, there are many problems with hot plugging devices. In the past, the operating system only had to search for the various devices connected to it on power-up, and once seen, the device would never go away. From the view of the device driver, it never expects to have the hardware that it is trying to control disappear. But with hot-pluggable devices, all of this changes.
Now the operating system has to have a mechanism that constantly detects if a new device appears. This usually is done by a bus-specific manager. This manager handles the scanning for new devices and recognizes this disappearance. It must be able to create system resources for the new device and pass control off to a specific driver. The device driver for a hot-pluggable device has to be able to recover gracefully when the hardware is removed and be able to bind itself to new hardware at any moment. Not only does the kernel need to know when devices are removed or added, but the user also should be notified when this happens. Other kinds of kernel events, such as the creation of network devices or the insertion of a laptop into a docking station, also would be useful for the user to know about.
This article describes the new framework in the Linux kernel for supporting USB and other hot-pluggable devices. It covers how the past implementation of PCMCIA loaded its drivers and the problems of that system. It presents the current method of loading USB and PCI drivers, and how this same framework can handle other kinds of user configuration issues easily.

The Past
Linux has had support for PCMCIA since 1995. In order for the PCMCIA core to be able to load drivers when a new device was inserted, it had a user-space program called cardmgr. The cardmgr program would receive notification from the kernel's PCMCIA core when a device had been inserted or removed and use that information to load or unload the proper driver for that card. It used a configuration file located at /etc/pcmcia/config to determine which driver should be used for which card. This configuration file needed to be kept up to date with which driver supported which card, or ranges of cards, and has grown to be over 1,500 lines long. Whenever a driver author added support for a new device, they had to modify two different files to enable the device to work properly.
As the USB core code became mature, the group realized that it also needed something like the PCMCIA system to be able to load and unload drivers dynamically when devices were inserted and removed. The group also noted that since USB and PCMCIA both needed this system, and that other kernel hot-plug subsystems also would use such a system, a generic hot-plug core would be useful. David Brownell posted an initial patch to the kernel (marc.theaimsgroup.com/?l=linux-usb-devel&m=96334011602320), enabling it to call out to a user-space program called /sbin/hotplug. This patch eventually was accepted, and other subsystems were modified to take advantage of it.

Let the Computer Do It Itself
All USB and PCI devices contain an identifier that describes either what kind of functions they support (like a USB audio or USB mass storage device), or if they do not support a class specification, they contain a unique vendor and product identifier. PCMCIA devices also contain these same kind of identifiers.
These identifiers are known by the PCI and USB kernel drivers, as they need to know which kind of devices they work properly for. The USB and PCI kernel drivers register with the kernel a list of the different types of devices that they support. This list is used to determine which driver will control which devices.
The kernel knows when and what kind of devices are inserted or removed from the system through the device bus core code (USB, FireWire, PCI, etc.). It can send this information to the user.
Taking these three pieces together (devices tell the computer what they are, drivers know what devices they support and the kernel knows what is going on) provides us with a solution to let the computer automatically load the proper driver whenever a new device is inserted.

/sbin/hotplug
The kernel hot-plug core provides a method for the kernel to notify user space that something has happened. The CONFIG_HOTPLUG configuration item needs to be selected for this code to be enabled. The notification happens when the kernel calls the executable listed in the global variable hotplug_path. When the kernel starts, hotplug_path is set to /sbin/hotplug, but the user can modify the value at /proc/sys/kernel/hotplug to change this. The kernel function call_usermodehelper() executes /sbin/hotplug.
As of kernel 2.4.14, the /sbin/hotplug method is being used by the PCI, USB, IEEE1394 and Network core subsystems. As time goes on, more subsystems will be converted to use it. Patches are available for the PnP-BIOS (notification when a laptop is inserted and removed from a docking station), Hot-Plug CPU, SCSI and IDE kernel subsystems. These are expected to be merged into the main kernel over time.
When /sbin/hotplug is called, different environment variables are set, depending on what action has just occurred.

PCI
PCI devices call /sbin/hotplug with the following arguments:
argv [0] = hotplug_pathargv [1] = "pci"argv [2] = 0and the system environment is set to the following:
HOME=/PATH=/sbin:/bin:/usr/sbin:/usr/binPCI_CLASS=class_codePCI_ID=vendor:devicePCI_SUBSYS_ID=subsystem_vendor:subsystem_devicePCI_SLOT_NAME=slot_nameACTION=actionThe action setting is add'' or remove'' depending on whether the device is being inserted or removed from the system. The class_code, vendor, subsystem_vendor, subsystem_device and slot_name environment settings represent the numerical values for the PCI device's information.

USB
USB devices call /sbin/hotplug with the following arguments:
argv [0] = hotplug_pathargv [1] = "usb"argv [2] = 0and the system environment is set to the following:
HOME=/PATH=/sbin:/bin:/usr/sbin:/usr/binACTION=actionPRODUCT=idVendor/idProduct/bcdDeviceTYPE=device_class/device_subclass/device_protocolThe action setting is add'' or remove'' depending on whether the device is being inserted or removed from the system, and idVendor, idProduct, bcdDevice, device_class, device_subclass and device_protocol are filled in with the information from the USB device's descriptors.

If the USB device's deviceClass is 0 then the environment variable INTERFACE is set to:
INTERFACE=class/subclass/protocolThis is because USB has a much more complex model for device configuration than PCI does.
If the USB subsystem is compiled with the usbdevfs filesystem enabled, the following environment variables also are set:
DEVFS=/proc/bus/usbDEVICE=/proc/bus/usb/bus_number/device_numberwhere bus_number and device_number are set to the bus number and device number that this specific USB device is assigned.

Network
The network core code calls /sbin/hotplug whenever a network device is registered or unregistered with the network subsystem, and /sbin/hotplug is called with the following arguments when called from the network core:
argv [0] = hotplug_pathargv [1] = "net"argv [2] = 0and the system environment is set to the following:
HOME=/PATH=/sbin:/bin:/usr/sbin:/usr/binINTERFACE=interfaceACTION=actionThe action setting is register'' or unregister'' depending on what happened in the network core, and interface is the name of the interface that just had the action applied to itself.

CPU
The Hot-Plug CPU patch (available at sourceforge.net/projects/lhcs) calls /sbin/hotplug after a CPU is removed or added to the system, and /sbin/hotplug is called with the following arguments:
argv [0] = hotplug_pathargv [1] = "cpu"argv [2] = 0and the system environment is set to the following:
HOME=/PATH=/sbin:/bin:/usr/sbin:/usr/binCPU=cpu_numberACTION=actionThe action setting is add'' or remove'' depending on what happened to the CPU, and cpu_number is the number of the CPU that just had the action applied to itself.

Examples
The /sbin/hotplug script can be a very simple script if you only want it to control a small number of devices. For example, if you have a USB mouse and wish to load and unload the kernel driver whenever the mouse is inserted or removed, the following script, located at /sbin/hotplug, would be sufficient:
#!/bin/shif [ "$1" = "usb" ]; then if [ "$INTERFACE" = "3/1/2" ]; then        if [ "$ACTION" = "add" ]; then modprobe usbmouse else rmmod usbmouse fi fifiOr if you want to run ColdSync (<FONT color="#44440a" href="http://www.ooblick.com/software/coldsync" target="_blank" [url=]www.ooblick.com/software/coldsync[/url]) automatically when you connect your USB HandSpring Visor to the computer, the following script located at /sbin/hotplug would work well: #!/bin/shUSER=gregkhif [ "$1" = "usb" ]; then    if [ "$PRODUCT" = "82d/100/0" ]; then if [ "$ACTION" = "add" ]; then            modprobe visor            su $USER - -c "/usr/bin/coldsync" else rmmod visor fi fifiIf you want to make sure that your network devices always come up connected to the proper Ethernet card, the following /sbin/hotplug script, contributed by Sukadev Bhattiprolu, can do this: #!/bin/shif [ "$1" = "network" ]; then    if [ "$ACTION" = "register" ]; then nameif -r$INTERFACE -c /etc/mactab    fifiListing 1 shows a more complex example that can handle automatically loading and unloading modules for three different USB devices.

Listing 1. Script to Load and Unload Modules Automatically for Three Different USB Devices

Need for Automation
The previous small example shows the limitations of being forced to enter in all of the different device IDs manually, product IDs and such in order to keep a /sbin/hotplug script up to date with all of the different devices that the kernel knows about. Instead, it would be better for the kernel itself to specify the different types of devices that it supports in such a way that any user-space tools could read them. Thus was born a macro called MODULE_DEVICE_TABLE() that is used by all USB and PCI drivers. This macro describes which devices each specific driver can support. At compilation time, the build process extracts this information out of the driver and builds a table. The table is called modules.pcimap and modules.usbmap for all PCI and USB devices, respectively, and exists in the directory /lib/modules/kernel_version/.
For example, the following code snippet from drivers/net/eepro100.c:
static struct pci_device_id eepro100_pci_tbl[]__devinitdata = {    { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557,      PCI_ANY_ID, PCI_ANY_ID, },    { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82562ET,      PCI_ANY_ID, PCI_ANY_ID, },        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL          _82559ER, PCI_ANY_ID, PCI_ANY_ID,},        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL          _ID1029, PCI_ANY_ID, PCI_ANY_ID,},        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL          _ID1030, PCI_ANY_ID, PCI_ANY_ID,},        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL          _82801BA_7, PCI_ANY_ID, PCI_ANY_ID,},        { 0,}    };    MODULE_DEVICE_TABLE(pci, eepro100_pci_tbl);causes these lines to be added to the modules.pcimap file:
eepro100 0x00008086 0x00001229 0xffffffff 0xffffffff0x00000000 0x00000000 0x00000000eepro100 0x00008086 0x00001031 0xffffffff 0xffffffff0x00000000 0x00000000 0x00000000eepro100 0x00008086 0x00001209 0xffffffff 0xffffffff0x00000000 0x00000000 0x00000000eepro100 0x00008086 0x00001029 0xffffffff 0xffffffff0x00000000 0x00000000 0x00000000eepro100 0x00008086 0x00001030 0xffffffff 0xffffffff0x00000000 0x00000000 0x00000000eepro100 0x00008086 0x00002449 0xffffffff 0xffffffff0x00000000 0x00000000 0x00000000As the example shows, a PCI device can be specified by any of the same parameters that are passed to the /sbin/hotplug program.

A USB device can specify that it can accept only specific devices such as this example from drivers/usb/mdc800.c:
static struct usb_device_id  mdc800_table [] = {   { USB_DEVICE(MDC800_VENDOR_ID, MDC800_PRODUCT_ID) },   { } /* Terminating entry */};MODULE_DEVICE_TABLE(usb, mdc800_table);which causes the following line to be added to the modules.usbmap file:
mdc800 0x0003 0x055f 0xa800 0x0000 0x0000 0x00 0x000x00 0x00 0x00 0x00 0x00000000Or it can specify that it accepts any device that matches a specific USB class code, as in this example from drivers/usb/printer.c: static struct usb_device_id usblp_ids [] = {  { USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 1) },  { USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 2) },  { USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 3) },  { }    /* Terminating entry */};MODULE_DEVICE_TABLE(usb, usblp_ids);which causes the following lines to be added to the modules.usbmap file: printer 0x0380 0x0000 0x0000 0x0000 0x0000 0x00 0x000x00 0x07 0x01 0x01 0x00000000printer 0x0380 0x0000 0x0000 0x0000 0x0000 0x00 0x000x00 0x07 0x01 0x02 0x00000000printer 0x0380 0x0000 0x0000 0x0000 0x0000 0x00 0x000x00 0x07 0x01 0x03 0x00000000Again these USB examples show that the information in the modules.usbmap file matches the information provided to /sbin/hotplug by the kernel, enabling /sbin/hotplug to determine which driver to load without relying on a hand-generated table, as PCMCIA does.

Preprocessor Abuse
The macro MODULE_DEVICE_TABLE automatically creates two variables. For the example: MODULE_DEVICE_TABLE (usb, usblp_ids); the variables __module_usb_device_size and __module_usb_device_table are created and placed into the read-only data section and the initialized data section of the module, respectively. The variable __module_usb_device_size contains the value of the size of the struct usb_id structure, and __module_usb_device_table points to the usblp_ids structure. The usblp_ids variable is an array of usb_id structures with a terminating NULL structure at the end of the list.
When the depmod program is run, as part of the kernel installation process, it goes through every module looking for the symbol __module_usb_device_size to be present in the compiled module. If it finds it, it copies the data pointed to by the __module_usb_device_table symbol into a structure, extracts all of the information and writes it out to the modules.usbmap file, which is located in the module root directory. It does the same thing while looking for the __module_pci_device_size in creating the modules.pcimap file.
With the kernel module information exported to the files modules.usbmap and modules.pcimap, our version of /sbin/hotplug can look like Listing 2 [available at ftp.ssc.com/pub/lj/listings/issue96/5604.tgz]. This example only tests for a match of the USB product ID and vendor IDs. The Linux-Hotplug Project has created a set of scripts that covers all of the different subsystems that can call /sbin/hotplug. This enables drivers to be loaded automatically when new devices are inserted into the systems. It also starts up network services when network devices are seen. These scripts are released under the GPL and are available at linux-hotplug.sourceforge.net. Almost all major Linux distributions are currently shipping this package, so it is probably already on your machine.

The Future
The current /sbin/hotplug subsystem needs to be incorporated into other kernel systems, as they develop hot-plug capability. SCSI, IDE and other systems all have hot-plug patches available for kernel support but need to have script support, kernel macro support and modutils depmod support added in order to provide the user with a consistent experience.
As the kernel boots, and discovers new devices, it tries to spawn /sbin/hotplug, but since user space has not been initialized yet, it cannot run. This means that any USB or PCI devices that are needed at boot time need to be compiled into the kernel or exist in an initrd RAM disk image as a module. Sometime during the 2.5 development process, the initrd RAM disk image will be converted to contain an entire small user-space tree. This will allow /sbin/hotplug to be run during the boot process and load modules dynamically. Some links describing this disk image idea are:lwn.net/2001/0712/kernel.php3marc.theaimsgroup.com/?l=acpi4linux&m=99705696732868marc.theaimsgroup.com/?l=linux-kernel&m=99436439232254 and marc.theaimsgroup.com/?l=linux-kernel&m=99436253707952.
Because of the small space requirements of this RAM disk image, the dietHotplug program has been written. It is an implementation of the Linux-Hotplug bash scripts in C and does not require modules.*map files when the program runs. The executable size of the entire dietHotplug program is one-fifth of the size of the original modules.*map files themselves. The small size is due to the use of dietLibc (found at www.fefe.de/dietlibc) and other space-saving techniques. dietHotplug will undergo more development as the 2.5 kernel requirements are more fully known. dietHotplug can be downloaded from the Linux-Hotplug site.

Acknowledgements
I would like to thank David Brownell who wrote the original /sbin/hotplug kernel patch and most of the Linux Hotplug scripts. Without his persistence, Linux would not have this user-friendly feature. I also would like to acknowledge the entire Linux USB development team, who have provided a solid kernel subsystem in a relatively short amount of time.
Keith Owens wrote the supporting code in the depmod utility and has endured constant changes to the format of the MODULE_DEVICE_TABLE() USB structure.
The other developers on the linux-hotplug-devel mailing list who have helped with their patches and feedback on the hot-plug scripts also deserve recognition, along with the wonderful Linux distribution-specific support that Debian, Red Hat and Mandrake have provided.
This article was based upon a paper and presentation that I gave at the 2001 Ottawa Linux Symposium.
Greg Kroah-Hartman is currently the Linux USB and PCI Hotplug kernel maintainer. He works for IBM, doing various LInux kernel-related things and can be reached at greg@kroah.com.
• 本文已收录于以下专栏：

linux中的热插拔和mdev机制

mdev是busybox自带的一个简化版的udev 作用是在系统启动和热插拔 或动态加载驱动程序时，自动产生驱动程序所需的节点文件，在文件系统中的/dev目录下的设备节点都是由mdev创建的 md...

Qt程序自动寻找依赖的动态库

Linux热插拔及mdev机制

• 2017年07月19日 20:16
• 4KB
• 下载

Linux 2.6.10内核下PCI Express Native热插拔框架的实现机制

• 2009年05月15日 22:12
• 269KB
• 下载

Linux热插拔处理机制

举报原因： 您举报文章：Linux 热插拔（Hot Plug）处理机制系列 色情 政治 抄袭 广告 招聘 骂人 其他 (最多只允许输入30个字)