为什么devfs 会被udev取代?
首先明确一点
udev 运行在用户空间 (内核版本2.6及以上)
devfs 运行在内核空间(内核版本 2.4)
Linux 设计中强调的一个基本观点是机制和策略的分离。
机制是做某样事情的固定步骤、方法,而策略就是每个步骤所采取的不同方式。
机制是相对固定的,而每个步骤采用的策略是不固定的。
机制是稳定的,而策略则是灵活的,因此在linux内核中,不应该实现策略
比如Linux 提供API可以让人把县城优先级调高或者调低,或者调整调度策略为SCHED_FIFO,
但是Linux内核本身却不管谁高谁低。
提供API属于机制,谁高谁低属于策略,所以应该是应该程序自己去告诉内核要高或者低,而内核不管这些杂事。
因此属于策略的东西应该被移动用户空间中,谁爱给那个设备创建什么名字或者想做更多的处理,谁自己去设定。
内核只管把这些信息告诉用户就可以了。
这就是位于内核空间的devfs应该被位于用户空间的udev取代的原因
udev 完全在用户态工作,利用设备加入或移除时内核所发送的热插拔事件(hotplug Event)来工作。
在热插拔时,设备的详细信息会由内核通过netlink套接字发送出来,发出的事件叫uevent.
udev的设备命名策略、权限控制和事件处理都是在用户态完成的,它利用从内核收到的信息来进行创建
设备文件节点等工作
devfs 与 udev 的另一个显著区别在于:采用devfs,当一个并不存在的/dev节点被打开的时候,devfs能自动加载对应的驱动,而udev则不这么做。这是因为udev的设计者认为Linux应该在设备被发现的时候加载驱动模块,而不是当它被访问的时候。
udev的设计者认为devfs所提供的打开/dev节点时自动加载驱动的功能对一个配置正确的计算机来说是多余的。系统中所有的设备都应该产生热插拔事件并加载恰当的驱动,而udev能注意这点并且为它创建对应的设备节点
本代码就是从内核通过netlink接收热插拔事件并显示出来
#include#include #include #include #include #include #include #include static void die(char *s) { write(2,s,strlen(s)); exit(1); } int main(int argc,char *argv[]) { struct sockaddr_nl nls; struct pollfd pfd; char buf[512]; //open hotplug event netlink socket memset(&nls, 0, sizeof(struct sockaddr_nl)); nls.nl_family = AF_NETLINK; nls.nl_pid = getpid(); nls.nl_groups = -1; pfd.events = POLLIN; pfd.fd = socket(PF_NETLINK , SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); if(pfd.fd == -1) die("Not rootn"); //Listen to netlink socket if (bind(pfd.fd ,(void *)&nls , sizeof(struct sockaddr_nl))) die("Bind failedn"); while(-1 != poll(&pfd ,1,-1)) { int i , len = recv(pfd.fd,buf,sizeof(buf),MSG_DONTWAIT); if(len == -1) die("recvn"); //print the data to stdout i = 0; while (i < len) { printf("%sn",buf +i); i += strlen(buf + i) +1; } } die("polln"); //dear gcc;shut up return 0; }
上文摘抄自《Linux设备驱动开发详解:基于最新的Linux 4.0内核》
Makefile文件
# make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- SRC = main.c OBJ = main all: $(CROSS_COMPILE)gcc $(SRC) -o $(OBJ) clean: rm $(OBJ) $(OBJ).o
手动触发uevent
echo add > /sys/module/psmouse
此时就能看到信息流被打印出来了
如果提示没有权限这样操作,可以用一个U盘插入电脑,也能看到内核发出的netlink 信息



