内核检测到USB设备的插入之后,需要通知用户空间进程来处理。目前有2种通知方式:
1.内核调用call_usermodehelper_setup()/call_usermodehelper_exec()从而运行用户空间进程来处理。可以通过/sys/kernel/uevent_helper或者/proc/sys/kernel/hotplug来配置,指定用户空间可执行程序的路径。。
2.调用netlink_broadcast_filtered(),通过netlink的方式,将事件发送到用户空间进程。
对于openwrt来说,他采用的是第二种方式。那么是哪个进程在监听这类事件呢?是procd这个进程。关于procd进程的启动,可以参照以下文章:
https://blog.csdn.net/angan4532/article/details/102303089
那么procd进程启动时,就会创建一个NETLINK_KOBJECT_UEVENT类型的netlink的socket连接到内核。当内核检测到事件后,就通过这个netlink socket 将uevent消息发送到procd.
那么procd收到uevent消息之后,对不同的消息会根据用户设定的规则进行不同的处理。这个规则是由/etc/hotplug.json指定的。
下面看一下这个配置文件的内容:
[router] /etc # cat hotplug.json [ [ "case", "ACTION", { "add": [ [ "if", [ "and", [ "has", "MAJOR" ], [ "has", "MINOR" ], ], [ [ "if", [ "or", [ "eq", "DEVNAME", [ "null", "full", "ptmx", "zero" ], ], [ "regex", "DEVNAME", [ "^gpio", "^hvc" ], ], ], [ [ "makedev", "/dev/%DEVNAME%", "0666" ], [ "return" ], ] ], [ "if", [ "or", [ "eq", "DEVNAME", "mapper/control" ], [ "regex", "DEVPATH", "^ppp" ], ], [ [ "makedev", "/dev/%DEVNAME%", "0600" ], [ "return" ], ], ], [ "if", [ "has", "DEVNAME" ], [ "makedev", "/dev/%DEVNAME%", "0644" ], ], ], ], [ "if", [ "has", "FIRMWARE" ], [ [ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ], [ "load-firmware", "/lib/firmware" ], [ "return" ] ] ], ], "remove" : [ [ "if", [ "and", [ "has", "DEVNAME" ], [ "has", "MAJOR" ], [ "has", "MINOR" ], ], [ "rm", "/dev/%DEVNAME%" ] ] ] } ], [ "if", [ "eq", "SUBSYSTEM", "platform" ], [ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ] ], [ "if", [ "and", [ "has", "BUTTON" ], [ "eq", "SUBSYSTEM", "button" ], ], [ "exec", "/etc/rc.button/%BUTTON%" ] ], [ "if", [ "eq", "SUBSYSTEM", [ "net", "input", "usb", "usbmisc", "ieee1394", "block", "atm", "zaptel", "tty", "button", "dump" ] ], [ "exec", "/sbin/hotplug-call", "%SUBSYSTEM%" ] ], [ "if", [ "and", [ "eq", "SUBSYSTEM", "usb-serial" ], [ "regex", "DEVNAME", [ "^ttyUSB", "^ttyACM" ] ], ], [ "exec", "/sbin/hotplug-call", "tty" ] ], ] [router] /etc #
可以看到,这个规则文件里面,对于不同类型的uevent都指定了不同的处理方式。比方说对于usb存储设备,他首先会用mkdev来创建device,然后会调用/sbin/hotplug-call,并传入一个参数SUBSYSTEM。
/sbin/hotplug-call是一个脚本程序:
[router] /etc # cat /sbin/hotplug-call #!/bin/sh # Copyright (C) 2006-2010 OpenWrt.org export HOTPLUG_TYPE="$1" . /lib/functions.sh PATH=/usr/sbin:/usr/bin:/sbin:/bin LOGNAME=root USER=root export PATH LOGNAME USER export DEVICENAME="${DEVPATH##*/}" [ \! -z "$1" -a -d /etc/hotplug.d/$1 ] && { for script in $(ls /etc/hotplug.d/$1/* 2>&-); do ( [ -f $script ] && . $script ); done } [router] /etc #
这个脚本会调用/etc/hotplug.d/$SUBSYSTEM下面的所有脚本。这个脚本用户可以自己指定。那么对于USB存储设备来说,我们可能需要将这个设备mount到文件系统。